diff --git a/src/syscall/fs.rs b/src/syscall/fs.rs
index a271e5d3148b2224ab5a6adfdfb0d85eb53eb5b8..0dee4987742196baeecc5be0f4ff21cf6e2780fd 100644
--- a/src/syscall/fs.rs
+++ b/src/syscall/fs.rs
@@ -448,6 +448,27 @@ pub fn frename(fd: FileHandle, path: &str) -> Result<usize> {
     }
 }
 
+/// File status
+pub fn fstat(fd: FileHandle, stat: &mut Stat) -> Result<usize> {
+    let file = {
+        let contexts = context::contexts();
+        let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
+        let context = context_lock.read();
+        context.get_file(fd).ok_or(Error::new(EBADF))?
+    };
+
+    let description = file.description.read();
+
+    let scheme = {
+        let schemes = scheme::schemes();
+        let scheme = schemes.get(description.scheme).ok_or(Error::new(EBADF))?;
+        Arc::clone(&scheme)
+    };
+    // Fill in scheme number as device number
+    stat.st_dev = description.scheme.into() as u64;
+    scheme.fstat(description.number, stat)
+}
+
 pub fn funmap_old(virtual_address: usize) -> Result<usize> {
     if virtual_address == 0 {
         Ok(0)
diff --git a/src/syscall/mod.rs b/src/syscall/mod.rs
index 3955af57029288c75a757512a1095adf7957fc2b..cb64c4c18a4b5cefc076a51888501b8d11dacd83 100644
--- a/src/syscall/mod.rs
+++ b/src/syscall/mod.rs
@@ -25,7 +25,7 @@ pub use self::process::*;
 pub use self::time::*;
 pub use self::validate::*;
 
-use self::data::{Map, SigAction, TimeSpec};
+use self::data::{Map, SigAction, Stat, TimeSpec};
 use self::error::{Error, Result, ENOSYS};
 use self::flag::{CloneFlags, MapFlags, PhysmapFlags, WaitFlags};
 use self::number::*;
@@ -74,7 +74,10 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize, bp: u
                         },
                         _ => file_op_slice(a, fd, validate_slice(c as *const u8, d)?),
                     }
-                    SYS_ARG_MSLICE => file_op_mut_slice(a, fd, validate_slice_mut(c as *mut u8, d)?),
+                    SYS_ARG_MSLICE => match a {
+                        SYS_FSTAT => fstat(fd, unsafe { validate_ref_mut(c as *mut Stat, d)? }),
+                        _ => file_op_mut_slice(a, fd, validate_slice_mut(c as *mut u8, d)?),
+                    },
                     _ => match a {
                         SYS_CLOSE => close(fd),
                         SYS_DUP => dup(fd, validate_slice(c as *const u8, d)?).map(FileHandle::into),
diff --git a/src/syscall/validate.rs b/src/syscall/validate.rs
index c5f3e23ee63eb15523539fcd2f44d0c181196984..2aac27a466bfc46e48e5bfa340ca34c7fb55ea1d 100644
--- a/src/syscall/validate.rs
+++ b/src/syscall/validate.rs
@@ -41,6 +41,16 @@ pub unsafe fn validate_ref<T>(ptr: *const T, size: usize) -> Result<&'static T>
     }
 }
 
+/// Convert a pointer and length to mutable reference, if valid
+pub unsafe fn validate_ref_mut<T>(ptr: *mut T, size: usize) -> Result<&'static mut T> {
+    if size == mem::size_of::<T>() {
+        validate(ptr as usize, mem::size_of::<T>(), false)?;
+        Ok(&mut *ptr)
+    } else {
+        Err(Error::new(EINVAL))
+    }
+}
+
 /// Convert a pointer and length to slice, if valid
 //TODO: Mark unsafe
 pub fn validate_slice<T>(ptr: *const T, len: usize) -> Result<&'static [T]> {