From ce3e54438c83d255130900e19bedd9fc69d055a6 Mon Sep 17 00:00:00 2001
From: 4lDO2 <4lDO2@protonmail.com>
Date: Thu, 18 May 2023 13:38:58 +0200
Subject: [PATCH] Release file_op's Arc before Scheme::handle.

This fixes https://gitlab.redox-os.org/redox-os/kernel/-/issues/117.
Redox's signal code switches the kernel stack to a signal stack, and if
that kernel stack runs SIGKILL's exit(), it won't run the Arc destructor
from the original stack.

We should really get rid of this stack-switching mechanism!
---
 src/syscall/fs.rs | 27 ++++++++++++---------------
 1 file changed, 12 insertions(+), 15 deletions(-)

diff --git a/src/syscall/fs.rs b/src/syscall/fs.rs
index 100214a6..e2c70f26 100644
--- a/src/syscall/fs.rs
+++ b/src/syscall/fs.rs
@@ -13,27 +13,24 @@ use crate::syscall::flag::*;
 
 
 pub fn file_op(a: usize, fd: FileHandle, c: usize, d: usize) -> Result<usize> {
-    let (file, pid, uid, gid) = {
-        let contexts = context::contexts();
-        let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
-        let context = context_lock.read();
-        let file = context.get_file(fd).ok_or(Error::new(EBADF))?;
-        (file, context.id, context.euid, context.egid)
+    let (scheme_id, scheme_number, current_cid, current_uid, current_gid) = match context::current()?.read() {
+        // TODO: Avoid semi-expensive Arc::clone by only accessing by reference?
+        ref current => match current.get_file(fd).ok_or(Error::new(EBADF))?.description.read() {
+            ref desc => {
+                (desc.scheme, desc.number, current.id, current.euid, current.egid)
+            }
+        }
     };
 
-    let scheme = {
-        let schemes = scheme::schemes();
-        let scheme = schemes.get(file.description.read().scheme).ok_or(Error::new(EBADF))?;
-        Arc::clone(scheme)
-    };
+    let scheme = Arc::clone(scheme::schemes().get(scheme_id).ok_or(Error::new(EBADF))?);
 
     let mut packet = Packet {
         id: 0,
-        pid: pid.into(),
-        uid,
-        gid,
+        pid: current_cid.into(),
+        uid: current_uid,
+        gid: current_gid,
         a,
-        b: file.description.read().number,
+        b: scheme_number,
         c,
         d
     };
-- 
GitLab