diff --git a/scheme/user.rs b/scheme/user.rs
index e5a016755d47bc75778af6c172a8079265fff92f..f2c797e4e83da3d471636a68dca4dbee9e11bfaa 100644
--- a/scheme/user.rs
+++ b/scheme/user.rs
@@ -65,76 +65,84 @@ impl UserInner {
     }
 
     fn capture_inner(&self, address: usize, size: usize, writable: bool) -> Result<usize> {
-        let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?;
-        let context = context_lock.read();
+        if size == 0 {
+            Ok(0)
+        } else {
+            let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?;
+            let context = context_lock.read();
 
-        let mut grants = context.grants.lock();
+            let mut grants = context.grants.lock();
 
-        let mut new_table = unsafe { InactivePageTable::from_address(context.arch.get_page_table()) };
-        let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(arch::USER_TMP_GRANT_OFFSET)));
+            let mut new_table = unsafe { InactivePageTable::from_address(context.arch.get_page_table()) };
+            let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(arch::USER_TMP_GRANT_OFFSET)));
 
-        let from_address = (address/4096) * 4096;
-        let offset = address - from_address;
-        let full_size = ((offset + size + 4095)/4096) * 4096;
-        let mut to_address = arch::USER_GRANT_OFFSET;
+            let from_address = (address/4096) * 4096;
+            let offset = address - from_address;
+            let full_size = ((offset + size + 4095)/4096) * 4096;
+            let mut to_address = arch::USER_GRANT_OFFSET;
 
-        let mut flags = entry::PRESENT | entry::NO_EXECUTE;
-        if writable {
-            flags |= entry::WRITABLE;
-        }
+            let mut flags = entry::PRESENT | entry::NO_EXECUTE;
+            if writable {
+                flags |= entry::WRITABLE;
+            }
 
-        for i in 0 .. grants.len() {
-            let start = grants[i].start_address().get();
-            if to_address + full_size < start {
-                grants.insert(i, Grant::new(
-                    VirtualAddress::new(from_address),
-                    VirtualAddress::new(to_address),
-                    full_size,
-                    flags,
-                    &mut new_table,
-                    &mut temporary_page
-                ));
-
-                return Ok(to_address + offset);
-            } else {
-                let pages = (grants[i].size() + 4095) / 4096;
-                let end = start + pages * 4096;
-                to_address = end;
+            for i in 0 .. grants.len() {
+                let start = grants[i].start_address().get();
+                if to_address + full_size < start {
+                    grants.insert(i, Grant::new(
+                        VirtualAddress::new(from_address),
+                        VirtualAddress::new(to_address),
+                        full_size,
+                        flags,
+                        &mut new_table,
+                        &mut temporary_page
+                    ));
+
+                    return Ok(to_address + offset);
+                } else {
+                    let pages = (grants[i].size() + 4095) / 4096;
+                    let end = start + pages * 4096;
+                    to_address = end;
+                }
             }
-        }
 
-        grants.push(Grant::new(
-            VirtualAddress::new(from_address),
-            VirtualAddress::new(to_address),
-            full_size,
-            flags,
-            &mut new_table,
-            &mut temporary_page
-        ));
+            grants.push(Grant::new(
+                VirtualAddress::new(from_address),
+                VirtualAddress::new(to_address),
+                full_size,
+                flags,
+                &mut new_table,
+                &mut temporary_page
+            ));
 
-        return Ok(to_address + offset);
+            Ok(to_address + offset)
+        }
     }
 
     pub fn release(&self, address: usize) -> Result<()> {
-        let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?;
-        let context = context_lock.read();
+        if address == 0 {
+            Ok(())
+        } else {
+            let context_lock = self.context.upgrade().ok_or(Error::new(ESRCH))?;
+            let context = context_lock.read();
 
-        let mut grants = context.grants.lock();
+            let mut grants = context.grants.lock();
 
-        let mut new_table = unsafe { InactivePageTable::from_address(context.arch.get_page_table()) };
-        let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(arch::USER_TMP_GRANT_OFFSET)));
+            let mut new_table = unsafe { InactivePageTable::from_address(context.arch.get_page_table()) };
+            let mut temporary_page = TemporaryPage::new(Page::containing_address(VirtualAddress::new(arch::USER_TMP_GRANT_OFFSET)));
 
-        for i in 0 .. grants.len() {
-            let start = grants[i].start_address().get();
-            let end = start + grants[i].size();
-            if address >= start && address < end {
-                grants.remove(i).destroy(&mut new_table, &mut temporary_page);
+            for i in 0 .. grants.len() {
+                let start = grants[i].start_address().get();
+                let end = start + grants[i].size();
+                if address >= start && address < end {
+                    grants.remove(i).destroy(&mut new_table, &mut temporary_page);
 
-                return Ok(());
+                    return Ok(());
+                }
             }
-        }
 
-        Err(Error::new(EFAULT))
+            Err(Error::new(EFAULT))
+        }
     }
 
     pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
diff --git a/syscall/validate.rs b/syscall/validate.rs
index 2ba6ef731f087d9d7a7f8b9799c26d54f9ff5311..361f58d94ff67af2a26da80ece4ec52a828b766b 100644
--- a/syscall/validate.rs
+++ b/syscall/validate.rs
@@ -1,15 +1,39 @@
-use core::slice;
+use core::{mem, slice};
 
+use arch::paging::{ActivePageTable, Page, VirtualAddress, entry};
 use syscall::error::*;
 
+fn validate(address: usize, size: usize, flags: entry::EntryFlags) -> Result<()> {
+    let active_table = unsafe { ActivePageTable::new() };
+
+    let start_page = Page::containing_address(VirtualAddress::new(address));
+    let end_page = Page::containing_address(VirtualAddress::new(address + size - 1));
+    for page in Page::range_inclusive(start_page, end_page) {
+        let page_flags = active_table.translate_page_flags(page).ok_or(Error::new(EFAULT))?;
+        if ! page_flags.contains(flags) {
+            return Err(Error::new(EFAULT));
+        }
+    }
+
+    Ok(())
+}
+
 /// Convert a pointer and length to slice, if valid
-/// TODO: Check validity
 pub fn validate_slice<T>(ptr: *const T, len: usize) -> Result<&'static [T]> {
-    Ok(unsafe { slice::from_raw_parts(ptr, len) })
+    if len == 0 {
+        Ok(&[])
+    } else {
+        validate(ptr as usize, len * mem::size_of::<T>(), entry::PRESENT /* TODO | entry::USER_ACCESSIBLE */)?;
+        Ok(unsafe { slice::from_raw_parts(ptr, len) })
+    }
 }
 
 /// Convert a pointer and length to slice, if valid
-/// TODO: Check validity
 pub fn validate_slice_mut<T>(ptr: *mut T, len: usize) -> Result<&'static mut [T]> {
-    Ok(unsafe { slice::from_raw_parts_mut(ptr, len) })
+    if len == 0 {
+        Ok(&mut [])
+    } else {
+        validate(ptr as usize, len * mem::size_of::<T>(), entry::PRESENT | entry::WRITABLE /* TODO | entry::USER_ACCESSIBLE */)?;
+        Ok(unsafe { slice::from_raw_parts_mut(ptr, len) })
+    }
 }