Browse Source

fix(futex): 修复futex系统调用参数处理逻辑 (#1321)

- 根据不同的futex命令类型正确处理第4个参数
- 对于WAIT系列操作,第4个参数被解释为超时指针
- 对于其他操作,第4个参数被解释为数值val2
- 仅在需要uaddr2的操作中校验uaddr2

Signed-off-by: longjin <longjin@DragonOS.org>
LoGin 3 weeks ago
parent
commit
978252d00a
1 changed files with 40 additions and 12 deletions
  1. 40 12
      kernel/src/libs/futex/syscall/sys_futex.rs

+ 40 - 12
kernel/src/libs/futex/syscall/sys_futex.rs

@@ -47,22 +47,39 @@ impl Syscall for SysFutexHandle {
         let uaddr = Self::uaddr(args);
         let operation = Self::operation(args)?;
         let val = Self::val(args);
-        let utime = Self::utime(args);
+        // 第4个参数:不同操作下语义不同(可能是 timeout 指针、val2、op 等)
+        let arg4 = Self::utime(args);
         let uaddr2 = Self::uaddr2(args);
         let val3 = Self::val3(args);
 
-        let mut timespec = None;
-        if utime != 0 {
-            let reader = UserBufferReader::new(
-                utime as *const PosixTimeSpec,
-                core::mem::size_of::<PosixTimeSpec>(),
-                frame.is_from_user(),
-            )?;
+        // 决定是否将第4参解释为超时指针(WAIT* 系列)或数值 val2(REQUEUE/WAKE_OP 等)
+        let cmd = FutexArg::from_bits(operation.bits() & FutexFlag::FUTEX_CMD_MASK.bits())
+            .ok_or(SystemError::ENOSYS)?;
 
-            timespec = Some(*reader.read_one_from_user::<PosixTimeSpec>(0)?);
-        }
+        let (timespec, val2): (Option<PosixTimeSpec>, u32) = match cmd {
+            // 与 Linux 语义一致:WAIT 使用相对超时;WAIT_BITSET/LOCK_PI2/WAIT_REQUEUE_PI 使用绝对时间(若带 CLOCKRT)
+            FutexArg::FUTEX_WAIT
+            | FutexArg::FUTEX_WAIT_BITSET
+            | FutexArg::FUTEX_WAIT_REQUEUE_PI
+            | FutexArg::FUTEX_LOCK_PI2 => {
+                if arg4 != 0 {
+                    let reader = UserBufferReader::new(
+                        arg4 as *const PosixTimeSpec,
+                        core::mem::size_of::<PosixTimeSpec>(),
+                        frame.is_from_user(),
+                    )?;
+                    (Some(*reader.read_one_from_user::<PosixTimeSpec>(0)?), 0)
+                } else {
+                    (None, 0)
+                }
+            }
+            _ => {
+                // 其他操作中,第4参为数值(如 REQUEUE 的 nr_requeue、WAKE_OP 的 nr_wake2 等)
+                (None, arg4 as u32)
+            }
+        };
 
-        do_futex(uaddr, operation, val, timespec, uaddr2, utime as u32, val3)
+        do_futex(uaddr, operation, val, timespec, uaddr2, val2, val3)
     }
 
     /// Formats the syscall parameters for display/debug purposes
@@ -133,10 +150,21 @@ pub(super) fn do_futex(
     val3: u32,
 ) -> Result<usize, SystemError> {
     verify_area(uaddr, core::mem::size_of::<u32>())?;
-    verify_area(uaddr2, core::mem::size_of::<u32>())?;
     let cmd = FutexArg::from_bits(operation.bits() & FutexFlag::FUTEX_CMD_MASK.bits())
         .ok_or(SystemError::ENOSYS)?;
 
+    // 仅在需要 uaddr2 的操作中校验它
+    match cmd {
+        FutexArg::FUTEX_REQUEUE
+        | FutexArg::FUTEX_CMP_REQUEUE
+        | FutexArg::FUTEX_WAKE_OP
+        | FutexArg::FUTEX_WAIT_REQUEUE_PI
+        | FutexArg::FUTEX_CMP_REQUEUE_PI => {
+            verify_area(uaddr2, core::mem::size_of::<u32>())?;
+        }
+        _ => {}
+    }
+
     let mut flags = FutexFlag::FLAGS_MATCH_NONE;
 
     if !operation.contains(FutexFlag::FUTEX_PRIVATE_FLAG) {