From: =?utf-8?b?0L3QsNCx?= <nabijaczleweli@nabijaczleweli.xyz>
Date: Fri, 22 Aug 2025 17:29:39 +0200
Subject: Fix TOCTTOU on creating temporary file

---
 safecat.c | 18 ++++++------------
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/safecat.c b/safecat.c
index 17d1f5f..d90895f 100644
--- a/safecat.c
+++ b/safecat.c
@@ -45,7 +45,6 @@ int main(int argc, char *argv[]) {
   int   outfd    = 0;
   FILE *outfdf   = NULL;
   int destdirfd = -1;
-  struct stat filestat;
   unsigned int count = 0;
 
   /* Check that we were called with the correct number of arguments. */
@@ -65,17 +64,19 @@ int main(int argc, char *argv[]) {
   tempdirfd = stat_dir(tempdir);
   destdirfd = stat_dir(destdir);
 
-  /* Step 2:  Stat the temporary file.  Wait for ENOENT as a response. */
+  /* Step 4:  Create the file tempdir/time.MusecPpid.host idempotently */
   for(count=1;;count++) {
     /* Get the temporary filename to use now for dumping data. */
     mk_tempfile(&outfile);
-    if(fstatat(tempdirfd,outfile.s,&filestat,0) == -1 && errno == ENOENT) {
+    alarm(86400);
+    outfd = openat(tempdirfd,outfile.s,O_WRONLY | O_EXCL | O_CREAT | O_LARGEFILE,0666);
+    if(outfd != -1) {
       break;
     }
 
     /* Try up to 5 times, every 2 seconds. */
-    if(count == 5) {
-      strerr_die_x(111, "safecat: fatal: ","could not stat temporary file");
+    if(errno != EEXIST || count == 5) {
+      strerr_die_x(111, "safecat: fatal: ","could not create output file");
     }
 
     /* Wait 2 seconds, and try again. */
@@ -83,13 +84,6 @@ int main(int argc, char *argv[]) {
     sleep(2);
   }
 
-  /* Step 4:  Create the file tempdir/time.MusecPpid.host */
-  alarm(86400);
-  outfd = openat(tempdirfd,outfile.s,O_WRONLY | O_EXCL | O_CREAT | O_LARGEFILE,0666);
-  if(outfd == -1) {
-    strerr_die_sys(111,"safecat: fatal: ","couldn't create output file: ");
-  }
-
   outfdf = fdopen(outfd, "w");
   if (!outfdf) {
     unlinkat(tempdirfd,outfile.s,0);
