]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
util: Fix GetTempPathW TOCTOU race condition 3044/head
authorTobias Stoeckmann <tobias@stoeckmann.org>
Sun, 17 May 2026 13:49:57 +0000 (15:49 +0200)
committerTobias Stoeckmann <tobias@stoeckmann.org>
Sun, 17 May 2026 13:49:57 +0000 (15:49 +0200)
Currently, the code calls GetTempPathW to figure out required size for a
buffer larger enough to contain the temporary directory path, allocates
the memory, and then calls GetTempPathW again to populate the memory.

Since libarchive is designed with multi-threading in mind, the worst
situation would be that another thread modifies the environment variable
between these two calls.

Use a buffer of MAX_PATH + 1 (261) to basically cover all regular
situations. If long paths are enabled, reallocate until enough bytes
were available (32 kb is maximum) without another thread intefering.
Realistically, this will happen only once.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
libarchive/archive_util.c

index e725a6d7680add912b3e70727ead151792ca40db..9d63fe79fb97460cca5a79c297eec7ebd4dcf9fc 100644 (file)
@@ -252,22 +252,36 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
        if (template == NULL) {
                /* Get a temporary directory. */
                if (tmpdir == NULL) {
-                       size_t l;
-                       wchar_t *tmp;
+                       wchar_t buf[MAX_PATH + 1];
+                       wchar_t *p = buf, *buf2 = NULL;
+                       size_t l, s;
 
-                       l = GetTempPathW(0, NULL);
+                       s = MAX_PATH + 1;
+                       l = GetTempPathW((DWORD)s, buf);
                        if (l == 0) {
                                la_dosmaperr(GetLastError());
                                goto exit_tmpfile;
                        }
-                       tmp = malloc(l*sizeof(wchar_t));
-                       if (tmp == NULL) {
-                               errno = ENOMEM;
-                               goto exit_tmpfile;
+                       while (l > s) {
+                               wchar_t *tmp;
+
+                               s = l;
+                               tmp = realloc(buf2, s * sizeof(wchar_t));
+                               if (tmp == NULL) {
+                                       free(buf2);
+                                       errno = ENOMEM;
+                                       goto exit_tmpfile;
+                               }
+                               p = buf2 = tmp;
+                               l = GetTempPathW((DWORD)s, buf2);
+                               if (l == 0) {
+                                       free(buf2);
+                                       la_dosmaperr(GetLastError());
+                                       goto exit_tmpfile;
+                               }
                        }
-                       GetTempPathW((DWORD)l, tmp);
-                       archive_wstrcpy(&temp_name, tmp);
-                       free(tmp);
+                       archive_wstrcpy(&temp_name, p);
+                       free(buf2);
                } else {
                        if (archive_wstring_append_from_mbs(&temp_name, tmpdir,
                            strlen(tmpdir)) < 0)