From 02780057f0dad0c607f5e1d91ccab80e22cf15e4 Mon Sep 17 00:00:00 2001
From: Martin Welgemoed <git@mwelgemoed.nl>
Date: Thu, 7 Dec 2023 15:39:38 +0000
Subject: [PATCH] Fixed utimes segfault when given nullptr

---
 src/header/sys_time/mod.rs     | 31 ++++++++++++++++++++-----------
 src/platform/redox/libredox.rs | 24 +++++++++++++++++++-----
 2 files changed, 39 insertions(+), 16 deletions(-)

diff --git a/src/header/sys_time/mod.rs b/src/header/sys_time/mod.rs
index edb2fc92d..de7d34b6f 100644
--- a/src/header/sys_time/mod.rs
+++ b/src/header/sys_time/mod.rs
@@ -5,6 +5,7 @@ use crate::{
     header::time::timespec,
     platform::{types::*, Pal, PalSignal, Sys},
 };
+use core::ptr::null;
 
 pub const ITIMER_REAL: c_int = 0;
 pub const ITIMER_VIRTUAL: c_int = 1;
@@ -57,15 +58,23 @@ pub extern "C" fn gettimeofday(tp: *mut timeval, tzp: *mut timezone) -> c_int {
 #[no_mangle]
 pub unsafe extern "C" fn utimes(path: *const c_char, times: *const timeval) -> c_int {
     let path = CStr::from_ptr(path);
-    let times_spec = [
-        timespec {
-            tv_sec: (*times.offset(0)).tv_sec,
-            tv_nsec: ((*times.offset(0)).tv_usec as c_long) * 1000,
-        },
-        timespec {
-            tv_sec: (*times.offset(1)).tv_sec,
-            tv_nsec: ((*times.offset(1)).tv_usec as c_long) * 1000,
-        },
-    ];
-    Sys::utimens(path, times_spec.as_ptr())
+    // Nullptr is valid here, it means "use current time"
+    let times_spec = if times.is_null() {
+        null()
+    } else {
+        {
+            [
+                timespec {
+                    tv_sec: (*times.offset(0)).tv_sec,
+                    tv_nsec: ((*times.offset(0)).tv_usec as c_long) * 1000,
+                },
+                timespec {
+                    tv_sec: (*times.offset(1)).tv_sec,
+                    tv_nsec: ((*times.offset(1)).tv_usec as c_long) * 1000,
+                },
+            ]
+        }
+        .as_ptr()
+    };
+    Sys::utimens(path, times_spec)
 }
diff --git a/src/platform/redox/libredox.rs b/src/platform/redox/libredox.rs
index df67379f3..09686e588 100644
--- a/src/platform/redox/libredox.rs
+++ b/src/platform/redox/libredox.rs
@@ -3,7 +3,7 @@ use core::{slice, str};
 use syscall::{Error, Result, WaitFlags, EMFILE};
 
 use crate::{
-    header::{signal::sigaction, time::timespec},
+    header::{signal::sigaction, sys_stat::UTIME_NOW, time::timespec},
     platform::types::*,
 };
 
@@ -77,10 +77,24 @@ pub unsafe fn fstatvfs(
     Ok(())
 }
 pub unsafe fn futimens(fd: usize, times: *const timespec) -> syscall::Result<()> {
-    let times = times
-        .cast::<[timespec; 2]>()
-        .read()
-        .map(|ts| syscall::TimeSpec::from(&ts));
+    let times = if times.is_null() {
+        // null means set to current time using special UTIME_NOW value (tv_sec is ignored in that case)
+        [
+            syscall::TimeSpec {
+                tv_sec: 0,
+                tv_nsec: UTIME_NOW as c_int,
+            },
+            syscall::TimeSpec {
+                tv_sec: 0,
+                tv_nsec: UTIME_NOW as c_int,
+            },
+        ]
+    } else {
+        times
+            .cast::<[timespec; 2]>()
+            .read()
+            .map(|ts| syscall::TimeSpec::from(&ts))
+    };
     syscall::futimens(fd as usize, &times)?;
     Ok(())
 }
-- 
GitLab