15
15
*/
16
16
17
17
#include "php.h"
18
+ #include "zend_long.h"
18
19
#include "php_open_temporary_file.h"
20
+ #include "ext/random/php_random.h"
21
+ #include "zend_operators.h"
19
22
20
23
#include <errno.h>
21
24
#include <sys/types.h>
84
87
* SUCH DAMAGE.
85
88
*/
86
89
90
+ static const char base32alphabet [] = "0123456789abcdefghijklmnopqrstuv" ;
91
+
87
92
static int php_do_open_temporary_file (const char * path , const char * pfx , zend_string * * opened_path_p )
88
93
{
89
94
#ifdef PHP_WIN32
90
95
char * opened_path = NULL ;
91
96
size_t opened_path_len ;
92
- wchar_t * cwdw , * pfxw , pathw [MAXPATHLEN ];
97
+ wchar_t * cwdw , * random_prefix_w , pathw [MAXPATHLEN ];
93
98
#else
94
99
char opened_path [MAXPATHLEN ];
95
100
char * trailing_slash ;
96
101
#endif
102
+ uint64_t random ;
103
+ char * random_prefix ;
104
+ char * p ;
105
+ size_t len ;
97
106
char cwd [MAXPATHLEN ];
98
107
cwd_state new_state ;
99
108
int fd = -1 ;
@@ -128,34 +137,54 @@ static int php_do_open_temporary_file(const char *path, const char *pfx, zend_st
128
137
return -1 ;
129
138
}
130
139
140
+ /* Extend the prefix to increase randomness */
141
+ if (php_random_bytes_silent (& random , sizeof (random )) == FAILURE ) {
142
+ random = php_random_generate_fallback_seed ();
143
+ }
144
+
145
+ /* Use a compact encoding to not increase the path len too much, but do not
146
+ * mix case to avoid losing randomness on case-insensitive file systems */
147
+ len = strlen (pfx ) + 13 /* log(2**64)/log(strlen(base32alphabet)) */ + 1 ;
148
+ random_prefix = emalloc (len );
149
+ p = zend_mempcpy (random_prefix , pfx , strlen (pfx ));
150
+ while (p + 1 < random_prefix + len ) {
151
+ * p = base32alphabet [random % strlen (base32alphabet )];
152
+ p ++ ;
153
+ random /= strlen (base32alphabet );
154
+ }
155
+ * p = '\0' ;
156
+
131
157
#ifndef PHP_WIN32
132
158
if (IS_SLASH (new_state .cwd [new_state .cwd_length - 1 ])) {
133
159
trailing_slash = "" ;
134
160
} else {
135
161
trailing_slash = "/" ;
136
162
}
137
163
138
- if (snprintf (opened_path , MAXPATHLEN , "%s%s%sXXXXXX" , new_state .cwd , trailing_slash , pfx ) >= MAXPATHLEN ) {
164
+ if (snprintf (opened_path , MAXPATHLEN , "%s%s%sXXXXXX" , new_state .cwd , trailing_slash , random_prefix ) >= MAXPATHLEN ) {
165
+ efree (random_prefix );
139
166
efree (new_state .cwd );
140
167
return -1 ;
141
168
}
142
169
#endif
143
170
144
171
#ifdef PHP_WIN32
145
172
cwdw = php_win32_ioutil_any_to_w (new_state .cwd );
146
- pfxw = php_win32_ioutil_any_to_w (pfx );
147
- if (!cwdw || !pfxw ) {
173
+ random_prefix_w = php_win32_ioutil_any_to_w (random_prefix );
174
+ if (!cwdw || !random_prefix_w ) {
148
175
free (cwdw );
149
- free (pfxw );
176
+ free (random_prefix_w );
177
+ efree (random_prefix );
150
178
efree (new_state .cwd );
151
179
return -1 ;
152
180
}
153
181
154
- if (GetTempFileNameW (cwdw , pfxw , 0 , pathw )) {
182
+ if (GetTempFileNameW (cwdw , random_prefix_w , 0 , pathw )) {
155
183
opened_path = php_win32_ioutil_conv_w_to_any (pathw , PHP_WIN32_CP_IGNORE_LEN , & opened_path_len );
156
184
if (!opened_path || opened_path_len >= MAXPATHLEN ) {
157
185
free (cwdw );
158
- free (pfxw );
186
+ free (random_prefix_w );
187
+ efree (random_prefix );
159
188
efree (new_state .cwd );
160
189
return -1 ;
161
190
}
@@ -165,7 +194,8 @@ static int php_do_open_temporary_file(const char *path, const char *pfx, zend_st
165
194
* which means that opening it will fail... */
166
195
if (VCWD_CHMOD (opened_path , 0600 )) {
167
196
free (cwdw );
168
- free (pfxw );
197
+ free (random_prefix_w );
198
+ efree (random_prefix );
169
199
efree (new_state .cwd );
170
200
free (opened_path );
171
201
return -1 ;
@@ -174,7 +204,7 @@ static int php_do_open_temporary_file(const char *path, const char *pfx, zend_st
174
204
}
175
205
176
206
free (cwdw );
177
- free (pfxw );
207
+ free (random_prefix_w );
178
208
#elif defined(HAVE_MKSTEMP )
179
209
fd = mkstemp (opened_path );
180
210
#else
@@ -194,6 +224,7 @@ static int php_do_open_temporary_file(const char *path, const char *pfx, zend_st
194
224
}
195
225
#endif
196
226
efree (new_state .cwd );
227
+ efree (random_prefix );
197
228
return fd ;
198
229
}
199
230
/* }}} */
0 commit comments