Commit 53063e77fed6b9a133b35558416994bf43caf699

Edward Thomson 2022-02-07T23:11:11

futils: use our random function for mktemp `mktemp` on mingw is exceedingly deficient, using a single monotonically increasing alphabetic character and the pid. We need to use our own random number generator for temporary filenames.

diff --git a/src/futils.c b/src/futils.c
index 318e878..42c3595 100644
--- a/src/futils.c
+++ b/src/futils.c
@@ -10,6 +10,8 @@
 #include "runtime.h"
 #include "strmap.h"
 #include "hash.h"
+#include "rand.h"
+
 #include <ctype.h>
 #if GIT_WIN32
 #include "win32/findfile.h"
@@ -27,23 +29,20 @@ int git_futils_mkpath2file(const char *file_path, const mode_t mode)
 int git_futils_mktmp(git_str *path_out, const char *filename, mode_t mode)
 {
 	const int open_flags = O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC;
-	/* TMP_MAX is unrelated to mktemp but should provide a reasonable amount */
-	unsigned int tries = TMP_MAX;
+	unsigned int tries = 32;
 	int fd;
 
 	while (tries--) {
+		uint64_t rand = git_rand_next();
+
 		git_str_sets(path_out, filename);
-		git_str_puts(path_out, "_git2_XXXXXX");
+		git_str_puts(path_out, "_git2_");
+		git_str_encode_hexstr(path_out, (void *)&rand, sizeof(uint64_t));
 
 		if (git_str_oom(path_out))
 			return -1;
 
-		/* Using mktemp is safe when we open with O_CREAT | O_EXCL */
-		p_mktemp(path_out->ptr);
-		/* mktemp sets template to empty string on failure */
-		if (path_out->ptr[0] == '\0')
-			break;
-
+		/* Note that we open with O_CREAT | O_EXCL */
 		if ((fd = p_open(path_out->ptr, open_flags, mode)) >= 0)
 			return fd;
 	}
diff --git a/src/futils.h b/src/futils.h
index 1827cba..a82ec41 100644
--- a/src/futils.h
+++ b/src/futils.h
@@ -177,11 +177,12 @@ extern int git_futils_rmdir_r(const char *path, const char *base, uint32_t flags
  * protected directory; the file created will created will honor
  * the current `umask`.  Writes the filename into path_out.
  *
- * This function is *NOT* suitable for use in temporary directories
- * that are world writable.  It uses `mktemp` (for portability) and
- * many `mktemp` implementations use weak random characters.  It
- * should only be assumed to be suitable for atomically writing
- * a new file in a directory that you control.
+ * This function uses a high-quality PRNG seeded by the system's
+ * entropy pool _where available_ and falls back to a simple seed
+ * (time plus system information) when not.  This is suitable for
+ * writing within a protected directory, but the system's safe
+ * temporary file creation functions should be preferred where
+ * available when writing into world-writable (temp) directories.
  *
  * @return On success, an open file descriptor, else an error code < 0.
  */