From bac2509ccd74c5ee97c1c1c891164878c6e68e80 Mon Sep 17 00:00:00 2001
From: 4lDO2 <4lDO2@protonmail.com>
Date: Fri, 8 Jul 2022 12:27:17 +0200
Subject: [PATCH] Fix leaks for setuid/setgid too.

---
 src/platform/redox/mod.rs                | 19 +++++++++++++------
 src/platform/redox/redox-exec/src/lib.rs |  4 ++--
 2 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs
index ab5deedb..b456e85d 100644
--- a/src/platform/redox/mod.rs
+++ b/src/platform/redox/mod.rs
@@ -385,9 +385,12 @@ impl Pal for Sys {
         }
 
         if !is_interpreted && wants_setugid {
+            // Make sure the last file descriptor not covered by O_CLOEXEC is not leaked.
+            drop(file);
+
             let name = CStr::from_bytes_with_nul(b"escalate:\0").expect("string should be valid");
             // We are now going to invoke `escalate:` rather than loading the program ourselves.
-            let mut escalate_fd = match File::open(name, fcntl::O_WRONLY | fcntl::O_CLOEXEC) {
+            let mut escalate_fd = match File::open(name, fcntl::O_WRONLY) {
                 Ok(f) => f,
                 Err(_) => return -1,
             };
@@ -408,7 +411,7 @@ impl Pal for Sys {
             }
 
             // Second, we write the flattened args and envs with NUL characters separating
-            // individual items.
+            // individual items. This can be copied directly into the new executable's memory.
             if escalate_fd.write_all(&flatten_with_nul(args)).is_err() {
                 return -1;
             }
@@ -416,10 +419,14 @@ impl Pal for Sys {
                 return -1;
             }
 
-            // escalated will take care of the rest when responding to SYS_CLOSE.
-            // FIXME: close escalate_fd
-            if escalate_fd.write(&[]).is_err() {
-                return -1;
+            // Closing will notify the scheme, and from that point we will no longer have control
+            // over this process (unless it fails). We do this manually since drop cannot handle
+            // errors.
+            let fd = *escalate_fd as usize;
+            core::mem::forget(escalate_fd);
+
+            if let Err(err) = syscall::close(fd) {
+                return e(Err(err)) as c_int;
             }
 
             unreachable!()
diff --git a/src/platform/redox/redox-exec/src/lib.rs b/src/platform/redox/redox-exec/src/lib.rs
index aba5125c..aecb2b1b 100644
--- a/src/platform/redox/redox-exec/src/lib.rs
+++ b/src/platform/redox/redox-exec/src/lib.rs
@@ -61,7 +61,7 @@ where
     let mut tree = BTreeMap::new();
     tree.insert(0, PAGE_SIZE);
 
-    const BUFSZ: usize = 16384;
+    const BUFSZ: usize = 65536;
     let mut buf = vec! [0_u8; BUFSZ];
 
     read_all(*image_file as usize, Some(header.e_phoff), &mut phs).map_err(|_| Error::new(EIO))?;
@@ -91,7 +91,7 @@ where
             syscall::lseek(*image_file as usize, segment.p_offset as isize, SEEK_SET).map_err(|_| Error::new(EIO))?;
             syscall::lseek(*memory_fd, segment.p_vaddr as isize, SEEK_SET).map_err(|_| Error::new(EIO))?;
 
-            for size in core::iter::repeat(BUFSZ).take((segment.p_filesz as usize) / BUFSZ).chain(Some((segment.p_filesz as usize) % BUFSZ)) {
+            for size in core::iter::repeat(buf.len()).take((segment.p_filesz as usize) / buf.len()).chain(Some((segment.p_filesz as usize) % buf.len())) {
                 read_all(*image_file as usize, None, &mut buf[..size]).map_err(|_| Error::new(EIO))?;
                 let _ = syscall::write(*memory_fd, &buf[..size]).map_err(|_| Error::new(EIO))?;
             }
-- 
GitLab