From 244069cf43c28ee017959116430ec480b434dbd0 Mon Sep 17 00:00:00 2001
From: Jeremy Soller <jackpot51@gmail.com>
Date: Mon, 9 Oct 2017 20:12:08 -0600
Subject: [PATCH] Implement a capability namespace with no available schemes

---
 src/scheme/mod.rs        |   3 +-
 src/syscall/privilege.rs | 198 ++++++++++++++++++++++++++++-----------
 2 files changed, 146 insertions(+), 55 deletions(-)

diff --git a/src/scheme/mod.rs b/src/scheme/mod.rs
index 887828cc..74f0e492 100644
--- a/src/scheme/mod.rs
+++ b/src/scheme/mod.rs
@@ -99,7 +99,8 @@ impl SchemeList {
         let mut list = SchemeList {
             map: BTreeMap::new(),
             names: BTreeMap::new(),
-            next_ns: 0,
+            // Scheme namespaces always start at 1. 0 is a reserved namespace, the null namespace
+            next_ns: 1,
             next_id: 1
         };
         list.new_root();
diff --git a/src/syscall/privilege.rs b/src/syscall/privilege.rs
index e718196f..4351262d 100644
--- a/src/syscall/privilege.rs
+++ b/src/syscall/privilege.rs
@@ -73,25 +73,51 @@ pub fn setregid(rgid: u32, egid: u32) -> Result<usize> {
     let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
     let mut context = context_lock.write();
 
-    if (context.euid == 0
-    || rgid as i32 == -1
-    || rgid == context.egid
-    || rgid == context.rgid)
-    && (context.euid == 0
-    || egid as i32 == -1
-    || egid == context.egid
-    || egid == context.rgid)
-    {
-        if rgid as i32 != -1 {
-            context.rgid = rgid;
-        }
-        if egid as i32 != -1 {
-            context.egid = egid;
-        }
-        Ok(0)
-    } else {
-        Err(Error::new(EPERM))
+    let setrgid =
+        if context.euid == 0 {
+            // Allow changing RGID if root
+            true
+        } else if rgid == context.egid {
+            /// Allow changing RGID if used for EGID
+            true
+        } else if rgid == context.rgid {
+            /// Allow changing RGID if used for RGID
+            true
+        } else if rgid as i32 == -1 {
+            // Ignore RGID if -1 is passed
+            false
+        } else {
+            // Not permitted otherwise
+            return Err(Error::new(EPERM));
+        };
+
+    let setegid =
+        if context.euid == 0 {
+            // Allow changing EGID if root
+            true
+        } else if egid == context.egid {
+            /// Allow changing EGID if used for EGID
+            true
+        } else if egid == context.rgid {
+            /// Allow changing EGID if used for RGID
+            true
+        } else if egid as i32 == -1 {
+            // Ignore EGID if -1 is passed
+            false
+        } else {
+            // Not permitted otherwise
+            return Err(Error::new(EPERM));
+        };
+
+    if setrgid {
+        context.rgid = rgid;
+    }
+
+    if setegid {
+        context.egid = egid;
     }
+
+    Ok(0)
 }
 
 pub fn setrens(rns: SchemeNamespace, ens: SchemeNamespace) -> Result<usize> {
@@ -99,25 +125,63 @@ pub fn setrens(rns: SchemeNamespace, ens: SchemeNamespace) -> Result<usize> {
     let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
     let mut context = context_lock.write();
 
-    if (context.euid == 0
-    || rns.into() as isize == -1
-    || rns == context.ens
-    || rns == context.rns)
-    && (context.euid == 0
-    || ens.into() as isize == -1
-    || ens == context.ens
-    || ens == context.rns)
-    {
-        if rns.into() as isize != -1 {
-            context.rns = rns;
-        }
-        if ens.into() as isize != -1 {
-            context.ens = ens;
-        }
-        Ok(0)
-    } else {
-        Err(Error::new(EPERM))
+    let setrns =
+        if rns.into() == 0 {
+            // Allow entering capability mode
+            true
+        } else if context.rns.into() == 0 {
+            // Do not allow leaving capability mode
+            return Err(Error::new(EPERM));
+        } else if context.euid == 0 {
+            // Allow setting RNS if root
+            true
+        } else if rns == context.ens {
+            // Allow setting RNS if used for ENS
+            true
+        } else if rns == context.rns {
+            // Allow setting RNS if used for RNS
+            true
+        } else if rns.into() as isize == -1 {
+            // Ignore RNS if -1 is passed
+            false
+        } else {
+            // Not permitted otherwise
+            return Err(Error::new(EPERM));
+        };
+
+    let setens =
+        if ens.into() == 0 {
+            // Allow entering capability mode
+            true
+        } else if context.ens.into() == 0 {
+            // Do not allow leaving capability mode
+            return Err(Error::new(EPERM));
+        } else if context.euid == 0 {
+            // Allow setting ENS if root
+            true
+        } else if ens == context.ens {
+            // Allow setting ENS if used for ENS
+            true
+        } else if ens == context.rns {
+            // Allow setting ENS if used for RNS
+            true
+        } else if ens.into() as isize == -1 {
+            // Ignore ENS if -1 is passed
+            false
+        } else {
+            // Not permitted otherwise
+            return Err(Error::new(EPERM));
+        };
+
+    if setrns {
+        context.rns = rns;
+    }
+
+    if setens {
+        context.ens = ens;
     }
+
+    Ok(0)
 }
 
 pub fn setreuid(ruid: u32, euid: u32) -> Result<usize> {
@@ -125,23 +189,49 @@ pub fn setreuid(ruid: u32, euid: u32) -> Result<usize> {
     let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
     let mut context = context_lock.write();
 
-    if (context.euid == 0
-    || ruid as i32 == -1
-    || ruid == context.euid
-    || ruid == context.ruid)
-    && (context.euid == 0
-    || euid as i32 == -1
-    || euid == context.euid
-    || euid == context.ruid)
-    {
-        if ruid as i32 != -1 {
-            context.ruid = ruid;
-        }
-        if euid as i32 != -1 {
-            context.euid = euid;
-        }
-        Ok(0)
-    } else {
-        Err(Error::new(EPERM))
+    let setruid =
+        if context.euid == 0 {
+            // Allow setting RUID if root
+            true
+        } else if ruid == context.euid {
+            // Allow setting RUID if used for EUID
+            true
+        } else if ruid == context.ruid {
+            // Allow setting RUID if used for RUID
+            true
+        } else if ruid as i32 == -1 {
+            // Ignore RUID if -1 is passed
+            false
+        } else {
+            // Not permitted otherwise
+            return Err(Error::new(EPERM));
+        };
+
+    let seteuid =
+        if context.euid == 0 {
+            // Allow setting EUID if root
+            true
+        } else if euid == context.euid {
+            // Allow setting EUID if used for EUID
+            true
+        } else if euid == context.ruid {
+            // Allow setting EUID if used for RUID
+            true
+        } else if euid as i32 == -1 {
+            // Ignore EUID if -1 is passed
+            false
+        } else {
+            // Not permitted otherwise
+            return Err(Error::new(EPERM));
+        };
+
+    if setruid {
+        context.ruid = ruid;
     }
+
+    if seteuid {
+        context.euid = euid;
+    }
+
+    Ok(0)
 }
-- 
GitLab