From f38426e4586db4c5c91efa256ce7aae83c158558 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 5 Oct 2016 18:01:05 -0600 Subject: [PATCH] Implement unix permissions --- Makefile | 2 ++ drivers/ahcid/src/scheme.rs | 2 +- drivers/vesad/src/main.rs | 2 +- kernel/scheme/debug.rs | 2 +- kernel/scheme/env.rs | 2 +- kernel/scheme/event.rs | 2 +- kernel/scheme/initfs.rs | 6 ++++-- kernel/scheme/irq.rs | 2 +- kernel/scheme/root.rs | 2 +- kernel/scheme/user.rs | 10 +++++----- kernel/syscall/fs.rs | 28 ++++++++++++++-------------- kernel/syscall/mod.rs | 3 +++ kernel/syscall/process.rs | 32 ++++++++++++++++++++++++++++++++ libstd | 2 +- schemes/example/src/main.rs | 25 ++----------------------- schemes/redoxfs | 2 +- syscall/src/flag.rs | 31 ++++++++++++++++++------------- syscall/src/lib.rs | 4 ++-- syscall/src/scheme.rs | 16 ++++++++-------- 19 files changed, 99 insertions(+), 76 deletions(-) diff --git a/Makefile b/Makefile index 70307a1..43d0e21 100644 --- a/Makefile +++ b/Makefile @@ -288,6 +288,8 @@ $(BUILD)/filesystem.bin: \ -cp -RL filesystem/* $(BUILD)/filesystem/ -chown -R 0:0 $(BUILD)/filesystem/ -chown -R 1000:1000 $(BUILD)/filesystem/home/user/ + -chmod 700 $(BUILD)/filesystem/root/ + -chmod 700 $(BUILD)/filesystem/home/user/ sync -fusermount -u $(BUILD)/filesystem/ rm -rf $(BUILD)/filesystem/ diff --git a/drivers/ahcid/src/scheme.rs b/drivers/ahcid/src/scheme.rs index 73d46fc..eb2ec12 100644 --- a/drivers/ahcid/src/scheme.rs +++ b/drivers/ahcid/src/scheme.rs @@ -29,7 +29,7 @@ impl DiskScheme { } impl Scheme for DiskScheme { - fn open(&self, path: &[u8], _flags: usize) -> Result { + fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?; let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; diff --git a/drivers/vesad/src/main.rs b/drivers/vesad/src/main.rs index 5deb03e..1da58dd 100644 --- a/drivers/vesad/src/main.rs +++ b/drivers/vesad/src/main.rs @@ -70,7 +70,7 @@ impl DisplayScheme { } impl Scheme for DisplayScheme { - fn open(&self, path: &[u8], _flags: usize) -> Result { + fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { if path == b"input" { Ok(1) } else { diff --git a/kernel/scheme/debug.rs b/kernel/scheme/debug.rs index eed44ed..52d9a8b 100644 --- a/kernel/scheme/debug.rs +++ b/kernel/scheme/debug.rs @@ -33,7 +33,7 @@ pub extern fn debug_input(b: u8) { pub struct DebugScheme; impl Scheme for DebugScheme { - fn open(&self, _path: &[u8], _flags: usize) -> Result { + fn open(&self, _path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { Ok(0) } diff --git a/kernel/scheme/env.rs b/kernel/scheme/env.rs index 807c273..4a51485 100644 --- a/kernel/scheme/env.rs +++ b/kernel/scheme/env.rs @@ -32,7 +32,7 @@ impl EnvScheme { } impl Scheme for EnvScheme { - fn open(&self, path: &[u8], _flags: usize) -> Result { + fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { let path = str::from_utf8(path).map_err(|_err| Error::new(ENOENT))?.trim_matches('/'); let env_lock = { diff --git a/kernel/scheme/event.rs b/kernel/scheme/event.rs index 2dead8d..8229559 100644 --- a/kernel/scheme/event.rs +++ b/kernel/scheme/event.rs @@ -24,7 +24,7 @@ impl EventScheme { } impl Scheme for EventScheme { - fn open(&self, _path: &[u8], _flags: usize) -> Result { + fn open(&self, _path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { let handle = { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; diff --git a/kernel/scheme/initfs.rs b/kernel/scheme/initfs.rs index c3a795c..18696ed 100644 --- a/kernel/scheme/initfs.rs +++ b/kernel/scheme/initfs.rs @@ -35,7 +35,7 @@ impl InitFsScheme { } impl Scheme for InitFsScheme { - fn open(&self, path: &[u8], _flags: usize) -> Result { + fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { let path_utf8 = str::from_utf8(path).map_err(|_err| Error::new(ENOENT))?; let path_trimmed = path_utf8.trim_matches('/'); @@ -46,7 +46,7 @@ impl Scheme for InitFsScheme { self.handles.write().insert(id, Handle { path: entry.0, data: (entry.1).0, - mode: if (entry.1).1 { MODE_DIR } else { MODE_FILE }, + mode: if (entry.1).1 { MODE_DIR | 0o755 } else { MODE_FILE | 0o744 }, seek: 0 }); @@ -130,6 +130,8 @@ impl Scheme for InitFsScheme { let handle = handles.get(&id).ok_or(Error::new(EBADF))?; stat.st_mode = handle.mode; + stat.st_uid = 0; + stat.st_gid = 0; stat.st_size = handle.data.len() as u64; Ok(0) diff --git a/kernel/scheme/irq.rs b/kernel/scheme/irq.rs index 7ec202a..62fcb1a 100644 --- a/kernel/scheme/irq.rs +++ b/kernel/scheme/irq.rs @@ -7,7 +7,7 @@ use syscall::scheme::Scheme; pub struct IrqScheme; impl Scheme for IrqScheme { - fn open(&self, path: &[u8], _flags: usize) -> Result { + fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?; let id = path_str.parse::().or(Err(Error::new(ENOENT)))?; diff --git a/kernel/scheme/root.rs b/kernel/scheme/root.rs index e982c8f..c088d6e 100644 --- a/kernel/scheme/root.rs +++ b/kernel/scheme/root.rs @@ -25,7 +25,7 @@ impl RootScheme { } impl Scheme for RootScheme { - fn open(&self, path: &[u8], _flags: usize) -> Result { + fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { let context = { let contexts = context::contexts(); let context = contexts.current().ok_or(Error::new(ESRCH))?; diff --git a/kernel/scheme/user.rs b/kernel/scheme/user.rs index 96ba87e..542f01e 100644 --- a/kernel/scheme/user.rs +++ b/kernel/scheme/user.rs @@ -218,7 +218,7 @@ impl UserScheme { } impl Scheme for UserScheme { - fn open(&self, path: &[u8], flags: usize) -> Result { + fn open(&self, path: &[u8], flags: usize, _uid: u32, _gid: u32) -> Result { let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; let address = inner.capture(path)?; let result = inner.call(SYS_OPEN, address, path.len(), flags); @@ -226,15 +226,15 @@ impl Scheme for UserScheme { result } - fn mkdir(&self, path: &[u8], mode: usize) -> Result { + fn mkdir(&self, path: &[u8], mode: u16, _uid: u32, _gid: u32) -> Result { let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; let address = inner.capture(path)?; - let result = inner.call(SYS_MKDIR, address, path.len(), mode); + let result = inner.call(SYS_MKDIR, address, path.len(), mode as usize); let _ = inner.release(address); result } - fn rmdir(&self, path: &[u8]) -> Result { + fn rmdir(&self, path: &[u8], _uid: u32, _gid: u32) -> Result { let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; let address = inner.capture(path)?; let result = inner.call(SYS_RMDIR, address, path.len(), 0); @@ -242,7 +242,7 @@ impl Scheme for UserScheme { result } - fn unlink(&self, path: &[u8]) -> Result { + fn unlink(&self, path: &[u8], _uid: u32, _gid: u32) -> Result { let inner = self.inner.upgrade().ok_or(Error::new(ENODEV))?; let address = inner.capture(path)?; let result = inner.call(SYS_UNLINK, address, path.len(), 0); diff --git a/kernel/syscall/fs.rs b/kernel/syscall/fs.rs index adb690d..1c969f6 100644 --- a/kernel/syscall/fs.rs +++ b/kernel/syscall/fs.rs @@ -2,7 +2,7 @@ use context; use scheme; -use syscall::data::{Packet, Stat}; +use syscall::data::Packet; use syscall::error::*; pub fn file_op(a: usize, fd: usize, c: usize, d: usize) -> Result { @@ -70,11 +70,11 @@ pub fn getcwd(buf: &mut [u8]) -> Result { /// Open syscall pub fn open(path: &[u8], flags: usize) -> Result { - let path_canon = { + let (path_canon, uid, gid) = { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); - context.canonicalize(path) + (context.canonicalize(path), context.uid, context.gid) }; let mut parts = path_canon.splitn(2, |&b| b == b':'); @@ -88,7 +88,7 @@ pub fn open(path: &[u8], flags: usize) -> Result { let (scheme_id, scheme) = schemes.get_name(namespace).ok_or(Error::new(ENOENT))?; (scheme_id, scheme.clone()) }; - let file_id = scheme.open(reference_opt.unwrap_or(b""), flags)?; + let file_id = scheme.open(reference_opt.unwrap_or(b""), flags, uid, gid)?; (scheme_id, file_id) }; @@ -102,12 +102,12 @@ pub fn open(path: &[u8], flags: usize) -> Result { } /// mkdir syscall -pub fn mkdir(path: &[u8], mode: usize) -> Result { - let path_canon = { +pub fn mkdir(path: &[u8], mode: u16) -> Result { + let (path_canon, uid, gid) = { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); - context.canonicalize(path) + (context.canonicalize(path), context.uid, context.gid) }; let mut parts = path_canon.splitn(2, |&b| b == b':'); @@ -120,16 +120,16 @@ pub fn mkdir(path: &[u8], mode: usize) -> Result { let (_scheme_id, scheme) = schemes.get_name(namespace).ok_or(Error::new(ENOENT))?; scheme.clone() }; - scheme.mkdir(reference_opt.unwrap_or(b""), mode) + scheme.mkdir(reference_opt.unwrap_or(b""), mode, uid, gid) } /// rmdir syscall pub fn rmdir(path: &[u8]) -> Result { - let path_canon = { + let (path_canon, uid, gid) = { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); - context.canonicalize(path) + (context.canonicalize(path), context.uid, context.gid) }; let mut parts = path_canon.splitn(2, |&b| b == b':'); @@ -142,16 +142,16 @@ pub fn rmdir(path: &[u8]) -> Result { let (_scheme_id, scheme) = schemes.get_name(namespace).ok_or(Error::new(ENOENT))?; scheme.clone() }; - scheme.rmdir(reference_opt.unwrap_or(b"")) + scheme.rmdir(reference_opt.unwrap_or(b""), uid, gid) } /// Unlink syscall pub fn unlink(path: &[u8]) -> Result { - let path_canon = { + let (path_canon, uid, gid) = { let contexts = context::contexts(); let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; let context = context_lock.read(); - context.canonicalize(path) + (context.canonicalize(path), context.uid, context.gid) }; let mut parts = path_canon.splitn(2, |&b| b == b':'); @@ -164,7 +164,7 @@ pub fn unlink(path: &[u8]) -> Result { let (_scheme_id, scheme) = schemes.get_name(namespace).ok_or(Error::new(ENOENT))?; scheme.clone() }; - scheme.unlink(reference_opt.unwrap_or(b"")) + scheme.unlink(reference_opt.unwrap_or(b""), uid, gid) } /// Close syscall diff --git a/kernel/syscall/mod.rs b/kernel/syscall/mod.rs index f10469e..c0d389e 100644 --- a/kernel/syscall/mod.rs +++ b/kernel/syscall/mod.rs @@ -37,6 +37,9 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize }, SYS_CLASS_PATH => match a { SYS_OPEN => open(validate_slice(b as *const u8, c)?, d), + SYS_MKDIR => mkdir(validate_slice(b as *const u8, c)?, d as u16), + SYS_RMDIR => rmdir(validate_slice(b as *const u8, c)?), + SYS_UNLINK => unlink(validate_slice(b as *const u8, c)?), _ => unreachable!() }, _ => match a { diff --git a/kernel/syscall/process.rs b/kernel/syscall/process.rs index 3821b35..9519ef2 100644 --- a/kernel/syscall/process.rs +++ b/kernel/syscall/process.rs @@ -432,9 +432,33 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result { args.push(arg.to_vec()); // Must be moved into kernel space before exec unmaps all memory } + let (uid, gid) = { + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + (context.uid, context.gid) + }; + let file = syscall::open(path, 0)?; let mut stat = Stat::default(); syscall::file_op_mut_slice(syscall::number::SYS_FSTAT, file, &mut stat)?; + + let mut perm = stat.st_mode & 0o7; + if stat.st_uid == uid { + perm |= (stat.st_mode >> 6) & 0o7; + } + if stat.st_gid == gid { + perm |= (stat.st_mode >> 3) & 0o7; + } + if uid == 0 { + perm |= 0o7; + } + + if perm & 0o1 != 0o1 { + let _ = syscall::close(file); + return Err(Error::new(EACCES)); + } + //TODO: Only read elf header, not entire file. Then read required segments let mut data = vec![0; stat.st_size as usize]; syscall::file_op_mut_slice(syscall::number::SYS_READ, file, &mut data)?; @@ -458,6 +482,14 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result { drop(context.stack.take()); context.grants = Arc::new(Mutex::new(Vec::new())); + if stat.st_mode & syscall::flag::MODE_SETUID == syscall::flag::MODE_SETUID { + context.uid = stat.st_uid; + } + + if stat.st_mode & syscall::flag::MODE_SETGID == syscall::flag::MODE_SETGID { + context.gid = stat.st_gid; + } + // Map and copy new segments for segment in elf.segments() { if segment.p_type == program_header::PT_LOAD { diff --git a/libstd b/libstd index 60c282e..0484051 160000 --- a/libstd +++ b/libstd @@ -1 +1 @@ -Subproject commit 60c282e9b09cc37251d0229108398e7d7add99b9 +Subproject commit 0484051024316956c9e658ed7c3211f76a30a2f9 diff --git a/schemes/example/src/main.rs b/schemes/example/src/main.rs index d854ced..06ba194 100644 --- a/schemes/example/src/main.rs +++ b/schemes/example/src/main.rs @@ -10,8 +10,8 @@ use syscall::{Packet, Result, Scheme}; struct ExampleScheme; impl Scheme for ExampleScheme { - fn open(&self, path: &[u8], _flags: usize) -> Result { - println!("{}", unsafe { str::from_utf8_unchecked(path) }); + fn open(&self, path: &[u8], _flags: usize, uid: u32, gid: u32) -> Result { + println!("{} from {}:{}", unsafe { str::from_utf8_unchecked(path) }, uid, gid); Ok(0) } @@ -25,27 +25,6 @@ impl Scheme for ExampleScheme { } fn main(){ - { - let events = syscall::open("event:", 0).unwrap(); - - let a = syscall::open("display:", 0).unwrap(); - syscall::fevent(a, syscall::EVENT_READ).unwrap(); - let b = syscall::open("debug:", 0).unwrap(); - syscall::fevent(b, syscall::EVENT_READ).unwrap(); - - loop { - let mut event = syscall::Event::default(); - syscall::read(events, &mut event).unwrap(); - println!("{:?}", event); - - let mut buf = vec![0; event.data]; - syscall::read(event.id, &mut buf).unwrap(); - println!("{}", unsafe { ::std::str::from_utf8_unchecked(&buf) }); - } - - let _ = syscall::close(events); - } - thread::spawn(move || { let mut socket = File::create(":example").expect("example: failed to create example scheme"); let scheme = ExampleScheme; diff --git a/schemes/redoxfs b/schemes/redoxfs index c06edb2..3dcaad5 160000 --- a/schemes/redoxfs +++ b/schemes/redoxfs @@ -1 +1 @@ -Subproject commit c06edb232b48024a7a8e468dd5316d5b28a3eac9 +Subproject commit 3dcaad55fe6e82450c1691da5d515861a7deed0a diff --git a/syscall/src/flag.rs b/syscall/src/flag.rs index 73b4dd8..c3e7d91 100644 --- a/syscall/src/flag.rs +++ b/syscall/src/flag.rs @@ -25,25 +25,30 @@ pub const FUTEX_REQUEUE: usize = 2; pub const MAP_WRITE: usize = 1; pub const MAP_WRITE_COMBINE: usize = 2; +pub const MODE_TYPE: u16 = 0xF000; pub const MODE_DIR: u16 = 0x4000; pub const MODE_FILE: u16 = 0x8000; -pub const MODE_ALL: u16 = MODE_DIR | MODE_FILE; + +pub const MODE_PERM: u16 = 0x0FFF; +pub const MODE_SETUID: u16 = 0o4000; +pub const MODE_SETGID: u16 = 0o2000; pub const SEEK_SET: usize = 0; pub const SEEK_CUR: usize = 1; pub const SEEK_END: usize = 2; -pub const O_RDONLY: usize = 0; -pub const O_WRONLY: usize = 1; -pub const O_RDWR: usize = 2; -pub const O_NONBLOCK: usize = 4; -pub const O_APPEND: usize = 8; -pub const O_SHLOCK: usize = 0x10; -pub const O_EXLOCK: usize = 0x20; -pub const O_ASYNC: usize = 0x40; -pub const O_FSYNC: usize = 0x80; -pub const O_CREAT: usize = 0x200; -pub const O_TRUNC: usize = 0x400; -pub const O_EXCL: usize = 0x800; +pub const O_RDONLY: usize = 0x0000_0000; +pub const O_WRONLY: usize = 0x0001_0000; +pub const O_RDWR: usize = 0x0002_0000; +pub const O_NONBLOCK: usize = 0x0004_0000; +pub const O_APPEND: usize = 0x0008_0000; +pub const O_SHLOCK: usize = 0x0010_0000; +pub const O_EXLOCK: usize = 0x0020_0000; +pub const O_ASYNC: usize = 0x0040_0000; +pub const O_FSYNC: usize = 0x0080_0000; +pub const O_CLOEXEC: usize = 0x0100_0000; +pub const O_CREAT: usize = 0x0200_0000; +pub const O_TRUNC: usize = 0x0400_0000; +pub const O_EXCL: usize = 0x0800_0000; pub const WNOHANG: usize = 1; diff --git a/syscall/src/lib.rs b/syscall/src/lib.rs index 463503d..94b7e65 100644 --- a/syscall/src/lib.rs +++ b/syscall/src/lib.rs @@ -112,8 +112,8 @@ pub fn lseek(fd: usize, offset: isize, whence: usize) -> Result { unsafe { syscall3(SYS_LSEEK, fd, offset as usize, whence) } } -pub fn mkdir(path: &str, mode: usize) -> Result { - unsafe { syscall3(SYS_MKDIR, path.as_ptr() as usize, path.len(), mode) } +pub fn mkdir(path: &str, mode: u16) -> Result { + unsafe { syscall3(SYS_MKDIR, path.as_ptr() as usize, path.len(), mode as usize) } } pub fn nanosleep(req: &TimeSpec, rem: &mut TimeSpec) -> Result { diff --git a/syscall/src/scheme.rs b/syscall/src/scheme.rs index 43d1899..310bb88 100644 --- a/syscall/src/scheme.rs +++ b/syscall/src/scheme.rs @@ -5,10 +5,10 @@ use super::*; pub trait Scheme { fn handle(&self, packet: &mut Packet) { packet.a = Error::mux(match packet.a { - SYS_OPEN => self.open(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d), - SYS_MKDIR => self.mkdir(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d), - SYS_RMDIR => self.rmdir(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }), - SYS_UNLINK => self.unlink(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }), + SYS_OPEN => self.open(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d, packet.uid, packet.gid), + SYS_MKDIR => self.mkdir(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.d as u16, packet.uid, packet.gid), + SYS_RMDIR => self.rmdir(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid), + SYS_UNLINK => self.unlink(unsafe { slice::from_raw_parts(packet.b as *const u8, packet.c) }, packet.uid, packet.gid), SYS_DUP => self.dup(packet.b), SYS_READ => self.read(packet.b, unsafe { slice::from_raw_parts_mut(packet.c as *mut u8, packet.d) }), @@ -28,22 +28,22 @@ pub trait Scheme { /* Scheme operations */ #[allow(unused_variables)] - fn open(&self, path: &[u8], flags: usize) -> Result { + fn open(&self, path: &[u8], flags: usize, uid: u32, gid: u32) -> Result { Err(Error::new(ENOENT)) } #[allow(unused_variables)] - fn mkdir(&self, path: &[u8], mode: usize) -> Result { + fn mkdir(&self, path: &[u8], mode: u16, uid: u32, gid: u32) -> Result { Err(Error::new(ENOENT)) } #[allow(unused_variables)] - fn rmdir(&self, path: &[u8]) -> Result { + fn rmdir(&self, path: &[u8], uid: u32, gid: u32) -> Result { Err(Error::new(ENOENT)) } #[allow(unused_variables)] - fn unlink(&self, path: &[u8]) -> Result { + fn unlink(&self, path: &[u8], uid: u32, gid: u32) -> Result { Err(Error::new(ENOENT)) }