Skip to content

Commit c50feeb

Browse files
committed
Improve randomness of uploaded file names and files created by tempnam()
1 parent 8a87206 commit c50feeb

File tree

2 files changed

+51
-19
lines changed

2 files changed

+51
-19
lines changed

ext/standard/tests/file/tempnam_variation9.phpt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,17 @@ if (file_exists($file_path)) {
5757
--EXPECTF--
5858
*** Testing tempnam() maximum prefix size ***
5959
-- Iteration 0 --
60-
File name is => begin_%rx{7}%r_end%r.{6}%r
61-
File name length is => 23
60+
File name is => begin_%rx{7}%r_end%r.{14,22}%r
61+
File name length is => %r31|39%r
6262
-- Iteration 1 --
63-
File name is => begin_%rx{53}%r_end%r.{6}%r
64-
File name length is => 69
63+
File name is => begin_%rx{53}%r_end%r.{14,22}%r
64+
File name length is => %r77|85%r
6565
-- Iteration 2 --
66-
File name is => begin_%rx{54}%r_en%r.{6}%r
67-
File name length is => 69
66+
File name is => begin_%rx{54}%r_en%r.{14,22}%r
67+
File name length is => %r77|85%r
6868
-- Iteration 3 --
69-
File name is => begin_%rx{55}%r_e%r.{6}%r
70-
File name length is => 69
69+
File name is => begin_%rx{55}%r_e%r.{14,22}%r
70+
File name length is => %r77|85%r
7171
-- Iteration 4 --
72-
File name is => begin_%rx{57}%r%r.{6}%r
73-
File name length is => 69
72+
File name is => begin_%rx{57}%r%r.{14,22}%r
73+
File name length is => %r77|85%r

main/php_open_temporary_file.c

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
*/
1616

1717
#include "php.h"
18+
#include "zend_long.h"
1819
#include "php_open_temporary_file.h"
20+
#include "ext/random/php_random.h"
1921

2022
#include <errno.h>
2123
#include <sys/types.h>
@@ -89,11 +91,13 @@ static int php_do_open_temporary_file(const char *path, const char *pfx, zend_st
8991
#ifdef PHP_WIN32
9092
char *opened_path = NULL;
9193
size_t opened_path_len;
92-
wchar_t *cwdw, *pfxw, pathw[MAXPATHLEN];
94+
wchar_t *cwdw, *random_prefix_w, pathw[MAXPATHLEN];
9395
#else
9496
char opened_path[MAXPATHLEN];
9597
char *trailing_slash;
9698
#endif
99+
zend_long random;
100+
char *random_prefix;
97101
char cwd[MAXPATHLEN];
98102
cwd_state new_state;
99103
int fd = -1;
@@ -128,34 +132,60 @@ static int php_do_open_temporary_file(const char *path, const char *pfx, zend_st
128132
return -1;
129133
}
130134

135+
/* Extend the prefix to increase randoness */
136+
if (php_random_int(ZEND_LONG_MIN, ZEND_LONG_MAX, &random, /* should_throw */ false) == FAILURE) {
137+
/* Fallback to non-csprng */
138+
uint64_t t[4];
139+
php_random_status_state_xoshiro256starstar state;
140+
do {
141+
t[0] = php_random_generate_fallback_seed();
142+
t[1] = php_random_generate_fallback_seed();
143+
t[2] = php_random_generate_fallback_seed();
144+
t[3] = php_random_generate_fallback_seed();
145+
} while (UNEXPECTED(t[0] == 0 && t[1] == 0 && t[2] == 0 && t[3] == 0));
146+
147+
php_random_xoshiro256starstar_seed256(&state, t[0], t[1], t[2], t[3]);
148+
php_random_result result = php_random_algo_xoshiro256starstar.generate(&state);
149+
random = (zend_long) result.result;
150+
}
151+
152+
if (spprintf(&random_prefix, MAXPATHLEN, "%s" ZEND_XLONG_FMT, pfx, random) >= MAXPATHLEN) {
153+
efree(random_prefix);
154+
efree(new_state.cwd);
155+
return -1;
156+
}
157+
131158
#ifndef PHP_WIN32
132159
if (IS_SLASH(new_state.cwd[new_state.cwd_length - 1])) {
133160
trailing_slash = "";
134161
} else {
135162
trailing_slash = "/";
136163
}
137164

138-
if (snprintf(opened_path, MAXPATHLEN, "%s%s%sXXXXXX", new_state.cwd, trailing_slash, pfx) >= MAXPATHLEN) {
165+
if (snprintf(opened_path, MAXPATHLEN, "%s%s%sXXXXXX", new_state.cwd, trailing_slash, random_prefix) >= MAXPATHLEN) {
166+
efree(random_prefix);
139167
efree(new_state.cwd);
140168
return -1;
141169
}
142170
#endif
143171

144172
#ifdef PHP_WIN32
145173
cwdw = php_win32_ioutil_any_to_w(new_state.cwd);
146-
pfxw = php_win32_ioutil_any_to_w(pfx);
147-
if (!cwdw || !pfxw) {
174+
random_prefix_w = php_win32_ioutil_any_to_w(random_prefix);
175+
if (!cwdw || !random_prefix_w) {
148176
free(cwdw);
149-
free(pfxw);
177+
free(random_prefix_w);
178+
efree(random_prefix);
150179
efree(new_state.cwd);
151180
return -1;
152181
}
153182

154-
if (GetTempFileNameW(cwdw, pfxw, 0, pathw)) {
183+
if (GetTempFileNameW(cwdw, random_prefix_w, 0, pathw)) {
155184
opened_path = php_win32_ioutil_conv_w_to_any(pathw, PHP_WIN32_CP_IGNORE_LEN, &opened_path_len);
156185
if (!opened_path || opened_path_len >= MAXPATHLEN) {
157186
free(cwdw);
158-
free(pfxw);
187+
free(random_prefix_w);
188+
efree(random_prefix);
159189
efree(new_state.cwd);
160190
return -1;
161191
}
@@ -165,7 +195,8 @@ static int php_do_open_temporary_file(const char *path, const char *pfx, zend_st
165195
* which means that opening it will fail... */
166196
if (VCWD_CHMOD(opened_path, 0600)) {
167197
free(cwdw);
168-
free(pfxw);
198+
free(random_prefix_w);
199+
efree(random_prefix);
169200
efree(new_state.cwd);
170201
free(opened_path);
171202
return -1;
@@ -174,7 +205,7 @@ static int php_do_open_temporary_file(const char *path, const char *pfx, zend_st
174205
}
175206

176207
free(cwdw);
177-
free(pfxw);
208+
free(random_prefix_w);
178209
#elif defined(HAVE_MKSTEMP)
179210
fd = mkstemp(opened_path);
180211
#else
@@ -194,6 +225,7 @@ static int php_do_open_temporary_file(const char *path, const char *pfx, zend_st
194225
}
195226
#endif
196227
efree(new_state.cwd);
228+
efree(random_prefix);
197229
return fd;
198230
}
199231
/* }}} */

0 commit comments

Comments
 (0)