From d036c667a1ad7e104cd48846bf6b90961da8c1fb Mon Sep 17 00:00:00 2001 From: Jeremy Soller <jackpot51@gmail.com> Date: Sun, 16 Apr 2017 12:49:54 -0600 Subject: [PATCH] Perform cloexec logic in kernel --- src/context/file.rs | 2 ++ src/scheme/initfs.rs | 6 +---- src/scheme/pipe.rs | 48 ++++++++++++++-------------------------- src/scheme/root.rs | 7 +----- src/scheme/sys/iostat.rs | 6 ++--- src/syscall/fs.rs | 39 +++++++++++++++++++++++++++++++- src/syscall/mod.rs | 1 + src/syscall/process.rs | 24 ++++++++++++-------- 8 files changed, 77 insertions(+), 56 deletions(-) diff --git a/src/context/file.rs b/src/context/file.rs index 26e0863c..e7519b63 100644 --- a/src/context/file.rs +++ b/src/context/file.rs @@ -10,6 +10,8 @@ pub struct File { pub scheme: SchemeId, /// The number the scheme uses to refer to this file pub number: usize, + /// The flags passed to open or fcntl(SETFL) + pub flags: usize, /// If events are on, this is the event ID pub event: Option<usize>, } diff --git a/src/scheme/initfs.rs b/src/scheme/initfs.rs index 432e62af..827b0f99 100644 --- a/src/scheme/initfs.rs +++ b/src/scheme/initfs.rs @@ -65,17 +65,13 @@ impl Scheme for InitFsScheme { Err(Error::new(ENOENT)) } - fn dup(&self, id: usize, buf: &[u8]) -> Result<usize> { + fn dup(&self, id: usize, _buf: &[u8]) -> Result<usize> { let (path, flags, data, mode, seek) = { let handles = self.handles.read(); let handle = handles.get(&id).ok_or(Error::new(EBADF))?; (handle.path, handle.flags, handle.data, handle.mode, handle.seek) }; - if buf == b"exec" && flags & O_CLOEXEC == O_CLOEXEC { - return Err(Error::new(EBADF)); - } - let id = self.next_id.fetch_add(1, Ordering::SeqCst); self.handles.write().insert(id, Handle { path: path, diff --git a/src/scheme/pipe.rs b/src/scheme/pipe.rs index e03312c8..7de8636b 100644 --- a/src/scheme/pipe.rs +++ b/src/scheme/pipe.rs @@ -6,7 +6,7 @@ use scheme::{AtomicSchemeId, ATOMIC_SCHEMEID_INIT, SchemeId}; use sync::WaitCondition; use syscall::error::{Error, Result, EAGAIN, EBADF, EINVAL, EPIPE}; -use syscall::flag::{F_GETFL, F_SETFL, O_ACCMODE, O_CLOEXEC, O_NONBLOCK}; +use syscall::flag::{F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK}; use syscall::scheme::Scheme; /// Pipes list @@ -50,11 +50,11 @@ impl PipeScheme { } impl Scheme for PipeScheme { - fn dup(&self, id: usize, buf: &[u8]) -> Result<usize> { + fn dup(&self, id: usize, _buf: &[u8]) -> Result<usize> { let mut pipes = pipes_mut(); let read_option = if let Some(pipe) = pipes.0.get(&id) { - Some(pipe.dup(buf)?) + Some(pipe.dup()?) } else { None }; @@ -65,7 +65,7 @@ impl Scheme for PipeScheme { } let write_option = if let Some(pipe) = pipes.1.get(&id) { - Some(pipe.dup(buf)?) + Some(pipe.dup()?) } else { None }; @@ -152,20 +152,12 @@ impl PipeRead { } } - fn dup(&self, buf: &[u8]) -> Result<Self> { - if buf == b"exec" && self.flags.load(Ordering::SeqCst) & O_CLOEXEC == O_CLOEXEC { - Err(Error::new(EBADF)) - } else { - let mut flags = self.flags.load(Ordering::SeqCst); - if buf.is_empty() { - flags &= ! O_CLOEXEC; - } - Ok(PipeRead { - flags: AtomicUsize::new(flags), - condition: self.condition.clone(), - vec: self.vec.clone() - }) - } + fn dup(&self) -> Result<Self> { + Ok(PipeRead { + flags: AtomicUsize::new(self.flags.load(Ordering::SeqCst)), + condition: self.condition.clone(), + vec: self.vec.clone() + }) } fn fcntl(&self, cmd: usize, arg: usize) -> Result<usize> { @@ -226,20 +218,12 @@ impl PipeWrite { } } - fn dup(&self, buf: &[u8]) -> Result<Self> { - if buf == b"exec" && self.flags.load(Ordering::SeqCst) & O_CLOEXEC == O_CLOEXEC { - Err(Error::new(EBADF)) - } else { - let mut flags = self.flags.load(Ordering::SeqCst); - if buf.is_empty() { - flags &= ! O_CLOEXEC; - } - Ok(PipeWrite { - flags: AtomicUsize::new(flags), - condition: self.condition.clone(), - vec: self.vec.clone() - }) - } + fn dup(&self) -> Result<Self> { + Ok(PipeWrite { + flags: AtomicUsize::new(self.flags.load(Ordering::SeqCst)), + condition: self.condition.clone(), + vec: self.vec.clone() + }) } fn fcntl(&self, cmd: usize, arg: usize) -> Result<usize> { diff --git a/src/scheme/root.rs b/src/scheme/root.rs index 644144ae..cd08fd36 100644 --- a/src/scheme/root.rs +++ b/src/scheme/root.rs @@ -6,7 +6,6 @@ use spin::RwLock; use context; use syscall::error::*; -use syscall::flag::O_CLOEXEC; use syscall::scheme::Scheme; use scheme::{self, SchemeNamespace, SchemeId}; use scheme::user::{UserInner, UserScheme}; @@ -59,17 +58,13 @@ impl Scheme for RootScheme { } } - fn dup(&self, file: usize, buf: &[u8]) -> Result<usize> { + fn dup(&self, file: usize, _buf: &[u8]) -> Result<usize> { let mut handles = self.handles.write(); let inner = { let inner = handles.get(&file).ok_or(Error::new(EBADF))?; inner.clone() }; - if buf == b"exec" && inner.flags & O_CLOEXEC == O_CLOEXEC { - return Err(Error::new(EBADF)); - } - let id = self.next_id.fetch_add(1, Ordering::SeqCst); handles.insert(id, inner); diff --git a/src/scheme/sys/iostat.rs b/src/scheme/sys/iostat.rs index f7316bb1..9bb34e6c 100644 --- a/src/scheme/sys/iostat.rs +++ b/src/scheme/sys/iostat.rs @@ -36,7 +36,7 @@ pub fn resource() -> Result<Vec<u8>> { match schemes.get(file.scheme) { Some(scheme) => scheme.clone(), None => { - let _ = writeln!(string, " {:>4}: {:>8} {:>8}: no scheme", fd, file.scheme.into(), file.number); + let _ = writeln!(string, " {:>4}: {:>8} {:>8} {:>08X}: no scheme", fd, file.scheme.into(), file.number, file.flags); continue; } } @@ -46,10 +46,10 @@ pub fn resource() -> Result<Vec<u8>> { match scheme.fpath(file.number, &mut fpath) { Ok(path_len) => { let fname = str::from_utf8(&fpath[..path_len]).unwrap_or("?"); - let _ = writeln!(string, " {:>4}: {:>8} {:>8}: {}", fd, file.scheme.into(), file.number, fname); + let _ = writeln!(string, "{:>6}: {:>8} {:>8} {:>08X}: {}", fd, file.scheme.into(), file.number, file.flags, fname); }, Err(err) => { - let _ = writeln!(string, " {:>4}: {:>8} {:>8}: {}", fd, file.scheme.into(), file.number, err); + let _ = writeln!(string, "{:>6}: {:>8} {:>8} {:>08X}: {}", fd, file.scheme.into(), file.number, file.flags, err); } } } diff --git a/src/syscall/fs.rs b/src/syscall/fs.rs index bd02c52a..2b80c41d 100644 --- a/src/syscall/fs.rs +++ b/src/syscall/fs.rs @@ -6,7 +6,7 @@ use scheme::{self, FileHandle}; use syscall; use syscall::data::{Packet, Stat}; use syscall::error::*; -use syscall::flag::{MODE_DIR, MODE_FILE}; +use syscall::flag::{F_SETFL, O_ACCMODE, O_RDONLY, O_WRONLY, MODE_DIR, MODE_FILE}; pub fn file_op(a: usize, fd: FileHandle, c: usize, d: usize) -> Result<usize> { let (file, pid, uid, gid) = { @@ -112,6 +112,7 @@ pub fn open(path: &[u8], flags: usize) -> Result<FileHandle> { context.add_file(::context::file::File { scheme: scheme_id, number: file_id, + flags: flags, event: None, }).ok_or(Error::new(EMFILE)) } @@ -128,12 +129,14 @@ pub fn pipe2(fds: &mut [usize], flags: usize) -> Result<usize> { let read_fd = context.add_file(::context::file::File { scheme: scheme_id, number: read_id, + flags: O_RDONLY | flags & !O_ACCMODE, event: None, }).ok_or(Error::new(EMFILE))?; let write_fd = context.add_file(::context::file::File { scheme: scheme_id, number: write_id, + flags: O_WRONLY | flags & !O_ACCMODE, event: None, }).ok_or(Error::new(EMFILE))?; @@ -259,6 +262,7 @@ pub fn dup(fd: FileHandle, buf: &[u8]) -> Result<FileHandle> { context.add_file(::context::file::File { scheme: file.scheme, number: new_id, + flags: file.flags, event: None, }).ok_or(Error::new(EMFILE)) } @@ -293,11 +297,44 @@ pub fn dup2(fd: FileHandle, new_fd: FileHandle, buf: &[u8]) -> Result<FileHandle context.insert_file(new_fd, ::context::file::File { scheme: file.scheme, number: new_id, + flags: file.flags, event: None, }).ok_or(Error::new(EBADF)) } } +// File descriptor controls +pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize) -> Result<usize> { + let file = { + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + let file = context.get_file(fd).ok_or(Error::new(EBADF))?; + file + }; + + let res = { + let scheme = { + let schemes = scheme::schemes(); + let scheme = schemes.get(file.scheme).ok_or(Error::new(EBADF))?; + scheme.clone() + }; + scheme.fcntl(file.number, cmd, arg)? + }; + + if cmd == F_SETFL { + let contexts = context::contexts(); + let context_lock = contexts.current().ok_or(Error::new(ESRCH))?; + let context = context_lock.read(); + let mut files = context.files.lock(); + let mut file = files.get_mut(fd.into()).ok_or(Error::new(EBADF))?.ok_or(Error::new(EBADF))?; + let accmode = file.flags & O_ACCMODE; + file.flags = accmode | arg & !O_ACCMODE; + } + + Ok(res) +} + /// Register events for file pub fn fevent(fd: FileHandle, flags: usize) -> Result<usize> { let file = { diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs index be0eef9c..1d9cea69 100644 --- a/src/syscall/mod.rs +++ b/src/syscall/mod.rs @@ -54,6 +54,7 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize SYS_CLOSE => close(fd), SYS_DUP => dup(fd, validate_slice(c as *const u8, d)?).map(FileHandle::into), SYS_DUP2 => dup2(fd, FileHandle::from(c), validate_slice(d as *const u8, e)?).map(FileHandle::into), + SYS_FCNTL => fcntl(fd, c, d), SYS_FEVENT => fevent(fd, c), SYS_FUNMAP => funmap(b), _ => file_op(a, fd, c, d) diff --git a/src/syscall/process.rs b/src/syscall/process.rs index 96a0d953..a3028612 100644 --- a/src/syscall/process.rs +++ b/src/syscall/process.rs @@ -18,7 +18,7 @@ use scheme::{self, FileHandle}; use syscall; use syscall::data::Stat; use syscall::error::*; -use syscall::flag::{CLONE_VFORK, CLONE_VM, CLONE_FS, CLONE_FILES, WNOHANG}; +use syscall::flag::{CLONE_VFORK, CLONE_VM, CLONE_FS, CLONE_FILES, O_CLOEXEC, WNOHANG}; use syscall::validate::{validate_slice, validate_slice_mut}; pub fn brk(address: usize) -> Result<usize> { @@ -268,6 +268,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> { Some(context::file::File { scheme: file.scheme, number: new_number, + flags: file.flags, event: None, }) }, @@ -733,15 +734,19 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> { let new_file_option = if let Some(file) = *file_option { // Duplicate let result = { - let scheme_option = { - let schemes = scheme::schemes(); - schemes.get(file.scheme).map(|scheme| scheme.clone()) - }; - if let Some(scheme) = scheme_option { - let result = scheme.dup(file.number, b"exec"); - result - } else { + if file.flags & O_CLOEXEC == O_CLOEXEC { Err(Error::new(EBADF)) + } else { + let scheme_option = { + let schemes = scheme::schemes(); + schemes.get(file.scheme).map(|scheme| scheme.clone()) + }; + if let Some(scheme) = scheme_option { + let result = scheme.dup(file.number, b"exec"); + result + } else { + Err(Error::new(EBADF)) + } } }; @@ -766,6 +771,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> { Some(context::file::File { scheme: file.scheme, number: new_number, + flags: file.flags, event: None, }) }, -- GitLab