fix: credential robustness — NGROUPS_MAX, process-scope, cache readback
Kernel hardening (proc.rs +23 lines): - NGROUPS_MAX=65536 enforcement in Groups write handler - Reject non-u32-aligned writes with EINVAL - Process-scope propagation: setgroups() now fans out to ALL threads sharing the same owner_proc_id Relibc robustness: - setrlimit: EINVAL for unknown resources (was silent Ok) - posix_getgroups: kernel readback when cache is empty, fixes exec() cache-staleness gap Oracle audit fixes: H (kernel cap), E (alignment reject), G (process-scope), C (cache readback), B (rlimit errors)
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
diff --git a/src/context/context.rs b/src/context/context.rs
|
diff --git a/src/context/context.rs b/src/context/context.rs
|
||||||
index c97c516..1c86cec 100644
|
index c97c516..6d723f4 100644
|
||||||
--- a/src/context/context.rs
|
--- a/src/context/context.rs
|
||||||
+++ b/src/context/context.rs
|
+++ b/src/context/context.rs
|
||||||
@@ -148,6 +148,8 @@ pub struct Context {
|
@@ -148,6 +148,8 @@ pub struct Context {
|
||||||
@@ -19,8 +19,36 @@ index c97c516..1c86cec 100644
|
|||||||
|
|
||||||
#[cfg(feature = "syscall_debug")]
|
#[cfg(feature = "syscall_debug")]
|
||||||
syscall_debug_info: crate::syscall::debug::SyscallDebugInfo::default(),
|
syscall_debug_info: crate::syscall::debug::SyscallDebugInfo::default(),
|
||||||
|
@@ -479,6 +482,7 @@ impl Context {
|
||||||
|
uid: self.euid,
|
||||||
|
gid: self.egid,
|
||||||
|
pid: self.pid,
|
||||||
|
+ groups: self.groups.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/src/scheme/mod.rs b/src/scheme/mod.rs
|
||||||
|
index d30272c..9da2b28 100644
|
||||||
|
--- a/src/scheme/mod.rs
|
||||||
|
+++ b/src/scheme/mod.rs
|
||||||
|
@@ -777,6 +777,7 @@ pub struct CallerCtx {
|
||||||
|
pub pid: usize,
|
||||||
|
pub uid: u32,
|
||||||
|
pub gid: u32,
|
||||||
|
+ pub groups: alloc::vec::Vec<u32>,
|
||||||
|
}
|
||||||
|
impl CallerCtx {
|
||||||
|
pub fn filter_uid_gid(self, euid: u32, egid: u32) -> Self {
|
||||||
|
@@ -785,6 +786,7 @@ impl CallerCtx {
|
||||||
|
pid: self.pid,
|
||||||
|
uid: euid,
|
||||||
|
gid: egid,
|
||||||
|
+ groups: self.groups,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self
|
||||||
diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs
|
diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs
|
||||||
index 47588e1..30ae5ea 100644
|
index 47588e1..6ffb256 100644
|
||||||
--- a/src/scheme/proc.rs
|
--- a/src/scheme/proc.rs
|
||||||
+++ b/src/scheme/proc.rs
|
+++ b/src/scheme/proc.rs
|
||||||
@@ -105,6 +105,7 @@ enum ContextHandle {
|
@@ -105,6 +105,7 @@ enum ContextHandle {
|
||||||
@@ -51,24 +79,47 @@ index 47588e1..30ae5ea 100644
|
|||||||
HANDLES.write(token.token()).insert(
|
HANDLES.write(token.token()).insert(
|
||||||
id.get(),
|
id.get(),
|
||||||
Handle {
|
Handle {
|
||||||
@@ -1271,6 +1278,16 @@ impl ContextHandle {
|
@@ -1271,6 +1278,39 @@ impl ContextHandle {
|
||||||
guard.prio = (info.prio as usize).min(39);
|
guard.prio = (info.prio as usize).min(39);
|
||||||
Ok(size_of::<ProcSchemeAttrs>())
|
Ok(size_of::<ProcSchemeAttrs>())
|
||||||
}
|
}
|
||||||
+ Self::Groups => {
|
+ Self::Groups => {
|
||||||
|
+ const NGROUPS_MAX: usize = 65536;
|
||||||
|
+ if buf.len() % size_of::<u32>() != 0 {
|
||||||
|
+ return Err(Error::new(EINVAL));
|
||||||
|
+ }
|
||||||
+ let count = buf.len() / size_of::<u32>();
|
+ let count = buf.len() / size_of::<u32>();
|
||||||
|
+ if count > NGROUPS_MAX {
|
||||||
|
+ return Err(Error::new(EINVAL));
|
||||||
|
+ }
|
||||||
+ let mut groups = Vec::with_capacity(count);
|
+ let mut groups = Vec::with_capacity(count);
|
||||||
+ for chunk in buf.in_exact_chunks(size_of::<u32>()).take(count) {
|
+ for chunk in buf.in_exact_chunks(size_of::<u32>()).take(count) {
|
||||||
+ groups.push(chunk.read_u32()?);
|
+ groups.push(chunk.read_u32()?);
|
||||||
+ }
|
+ }
|
||||||
+ let mut guard = context.write(token.token());
|
+ let proc_id = {
|
||||||
+ guard.groups = groups;
|
+ let guard = context.read(token.token());
|
||||||
|
+ guard.owner_proc_id
|
||||||
|
+ };
|
||||||
|
+ {
|
||||||
|
+ let mut guard = context.write(token.token());
|
||||||
|
+ guard.groups = groups.clone();
|
||||||
|
+ }
|
||||||
|
+ if let Some(pid) = proc_id {
|
||||||
|
+ let mut contexts = context::contexts(token.downgrade());
|
||||||
|
+ let (contexts, mut t) = contexts.token_split();
|
||||||
|
+ for context_ref in contexts.iter() {
|
||||||
|
+ let mut ctx = context_ref.write(t.token());
|
||||||
|
+ if ctx.owner_proc_id == Some(pid) {
|
||||||
|
+ ctx.groups = groups.clone();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
+ Ok(count * size_of::<u32>())
|
+ Ok(count * size_of::<u32>())
|
||||||
+ }
|
+ }
|
||||||
ContextHandle::OpenViaDup => {
|
ContextHandle::OpenViaDup => {
|
||||||
let mut args = buf.usizes();
|
let mut args = buf.usizes();
|
||||||
|
|
||||||
@@ -1475,6 +1492,15 @@ impl ContextHandle {
|
@@ -1475,6 +1515,15 @@ impl ContextHandle {
|
||||||
debug_name,
|
debug_name,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,10 +39,10 @@ index 48cce34..d9f0141 100644
|
|||||||
(
|
(
|
||||||
unsafe { (*STATIC_PROC_INFO.get()).proc_fd.as_ref().unwrap() },
|
unsafe { (*STATIC_PROC_INFO.get()).proc_fd.as_ref().unwrap() },
|
||||||
diff --git a/redox-rt/src/sys.rs b/redox-rt/src/sys.rs
|
diff --git a/redox-rt/src/sys.rs b/redox-rt/src/sys.rs
|
||||||
index f0363a3..2fc04ef 100644
|
index f0363a3..db6e77d 100644
|
||||||
--- a/redox-rt/src/sys.rs
|
--- a/redox-rt/src/sys.rs
|
||||||
+++ b/redox-rt/src/sys.rs
|
+++ b/redox-rt/src/sys.rs
|
||||||
@@ -415,6 +415,31 @@ pub fn posix_getresugid() -> Resugid<u32> {
|
@@ -415,6 +415,54 @@ pub fn posix_getresugid() -> Resugid<u32> {
|
||||||
sgid,
|
sgid,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,13 +69,36 @@ index f0363a3..2fc04ef 100644
|
|||||||
+
|
+
|
||||||
+pub fn posix_getgroups() -> Vec<u32> {
|
+pub fn posix_getgroups() -> Vec<u32> {
|
||||||
+ let _sig_guard = tmp_disable_signals();
|
+ let _sig_guard = tmp_disable_signals();
|
||||||
+ DYNAMIC_PROC_INFO.lock().groups.clone()
|
+ let groups = DYNAMIC_PROC_INFO.lock().groups.clone();
|
||||||
|
+ if !groups.is_empty() {
|
||||||
|
+ return groups;
|
||||||
|
+ }
|
||||||
|
+ drop(_sig_guard);
|
||||||
|
+ posix_readback_groups().unwrap_or_default()
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+fn posix_readback_groups() -> Result<Vec<u32>> {
|
||||||
|
+ let auth_fd = crate::current_proc_fd().as_raw_fd();
|
||||||
|
+ let groups_path = alloc::format!("auth-{}-groups", auth_fd);
|
||||||
|
+ let thr_fd = crate::RtTcb::current().thread_fd();
|
||||||
|
+ let groups_fd = thr_fd.dup(groups_path.as_bytes())?;
|
||||||
|
+
|
||||||
|
+ let mut buf = vec![0u8; 65536 * size_of::<u32>()];
|
||||||
|
+ let n = syscall::read(groups_fd.as_raw_fd(), &mut buf)?;
|
||||||
|
+ let count = n / size_of::<u32>();
|
||||||
|
+ let mut groups = Vec::with_capacity(count);
|
||||||
|
+ for chunk in buf[..n].chunks_exact(size_of::<u32>()) {
|
||||||
|
+ groups.push(u32::from_ne_bytes(chunk.try_into().unwrap()));
|
||||||
|
+ }
|
||||||
|
+ let mut guard = DYNAMIC_PROC_INFO.lock();
|
||||||
|
+ guard.groups = groups.clone();
|
||||||
|
+ Ok(groups)
|
||||||
+}
|
+}
|
||||||
pub fn getens() -> Result<usize> {
|
pub fn getens() -> Result<usize> {
|
||||||
read_proc_meta(crate::current_proc_fd()).map(|meta| meta.ens as usize)
|
read_proc_meta(crate::current_proc_fd()).map(|meta| meta.ens as usize)
|
||||||
}
|
}
|
||||||
diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs
|
diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs
|
||||||
index 752339a..bff5be4 100644
|
index 752339a..a0b4304 100644
|
||||||
--- a/src/platform/redox/mod.rs
|
--- a/src/platform/redox/mod.rs
|
||||||
+++ b/src/platform/redox/mod.rs
|
+++ b/src/platform/redox/mod.rs
|
||||||
@@ -43,7 +43,7 @@ use crate::{
|
@@ -43,7 +43,7 @@ use crate::{
|
||||||
@@ -148,7 +171,7 @@ index 752339a..bff5be4 100644
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn getpagesize() -> usize {
|
fn getpagesize() -> usize {
|
||||||
@@ -736,21 +702,39 @@ impl Pal for Sys {
|
@@ -736,21 +702,45 @@ impl Pal for Sys {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getrlimit(resource: c_int, mut rlim: Out<rlimit>) -> Result<()> {
|
fn getrlimit(resource: c_int, mut rlim: Out<rlimit>) -> Result<()> {
|
||||||
@@ -175,11 +198,17 @@ index 752339a..bff5be4 100644
|
|||||||
- todo_skip!(0, "setrlimit({}, {:p}): not implemented", resource, rlim);
|
- todo_skip!(0, "setrlimit({}, {:p}): not implemented", resource, rlim);
|
||||||
- Err(Errno(EPERM))
|
- Err(Errno(EPERM))
|
||||||
+ unsafe fn setrlimit(resource: c_int, _rlim: *const rlimit) -> Result<()> {
|
+ unsafe fn setrlimit(resource: c_int, _rlim: *const rlimit) -> Result<()> {
|
||||||
+ if resource as u32 == RLIMIT_NOFILE as u32 || resource as u32 == RLIMIT_NPROC as u32 {
|
+ match resource as u32 {
|
||||||
+ Err(Errno(EPERM))
|
+ r if r == RLIMIT_NOFILE as u32 || r == RLIMIT_NPROC as u32 => Err(Errno(EPERM)),
|
||||||
+ } else {
|
+ r if r == RLIMIT_CORE as u32
|
||||||
+ // Other limits are silently ignored (compatibility)
|
+ || r == RLIMIT_STACK as u32
|
||||||
+ Ok(())
|
+ || r == RLIMIT_DATA as u32
|
||||||
|
+ || r == RLIMIT_AS as u32
|
||||||
|
+ || r == RLIMIT_FSIZE as u32 =>
|
||||||
|
+ {
|
||||||
|
+ Ok(())
|
||||||
|
+ }
|
||||||
|
+ _ => Err(Errno(EINVAL)),
|
||||||
+ }
|
+ }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,7 +227,7 @@ index 752339a..bff5be4 100644
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -913,23 +897,7 @@ impl Pal for Sys {
|
@@ -913,23 +903,7 @@ impl Pal for Sys {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,7 +252,7 @@ index 752339a..bff5be4 100644
|
|||||||
|
|
||||||
unsafe fn munlock(addr: *const c_void, len: usize) -> Result<()> {
|
unsafe fn munlock(addr: *const c_void, len: usize) -> Result<()> {
|
||||||
// Redox never swaps
|
// Redox never swaps
|
||||||
@@ -953,16 +921,7 @@ impl Pal for Sys {
|
@@ -953,16 +927,7 @@ impl Pal for Sys {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,7 +270,7 @@ index 752339a..bff5be4 100644
|
|||||||
|
|
||||||
unsafe fn nanosleep(rqtp: *const timespec, rmtp: *mut timespec) -> Result<()> {
|
unsafe fn nanosleep(rqtp: *const timespec, rmtp: *mut timespec) -> Result<()> {
|
||||||
let redox_rqtp = unsafe { redox_timespec::from(&*rqtp) };
|
let redox_rqtp = unsafe { redox_timespec::from(&*rqtp) };
|
||||||
@@ -1220,9 +1179,19 @@ impl Pal for Sys {
|
@@ -1220,9 +1185,19 @@ impl Pal for Sys {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn setgroups(size: size_t, list: *const gid_t) -> Result<()> {
|
unsafe fn setgroups(size: size_t, list: *const gid_t) -> Result<()> {
|
||||||
|
|||||||
Reference in New Issue
Block a user