|
1 # Source: upstream |
|
2 # http://git.php.net/?p=php-src.git;a=commit;h=df4bf28f9f104ca3ef78ed94b497859f15b004e5 |
|
3 # https://bugs.php.net/bug.php?id=70219 |
|
4 # Patches to ext/standard/var_unserializer.c and |
|
5 # ext/standard/var_unserializer.re adapted from upstream |
|
6 |
|
7 From df4bf28f9f104ca3ef78ed94b497859f15b004e5 Mon Sep 17 00:00:00 2001 |
|
8 From: Stanislav Malyshev <[email protected]> |
|
9 Date: Sun, 23 Aug 2015 13:27:59 -0700 |
|
10 Subject: [PATCH] Fix bug #70219 (Use after free vulnerability in session |
|
11 deserializer) |
|
12 |
|
13 --- |
|
14 ext/session/session.c | 36 +- |
|
15 ext/session/tests/session_decode_error2.phpt | 518 +++++------------------ |
|
16 ext/session/tests/session_decode_variation3.phpt | 2 +- |
|
17 ext/standard/tests/serialize/bug70219.phpt | 38 ++ |
|
18 ext/standard/var_unserializer.c | 68 +-- |
|
19 ext/standard/var_unserializer.re | 64 +-- |
|
20 6 files changed, 228 insertions(+), 498 deletions(-) |
|
21 create mode 100644 ext/standard/tests/serialize/bug70219.phpt |
|
22 |
|
23 diff --git a/ext/session/session.c b/ext/session/session.c |
|
24 index 306aba3..0e53c62 100644 |
|
25 --- a/ext/session/session.c |
|
26 +++ b/ext/session/session.c |
|
27 @@ -210,16 +210,18 @@ static char *php_session_encode(int *newlen TSRMLS_DC) /* {{{ */ |
|
28 } |
|
29 /* }}} */ |
|
30 |
|
31 -static void php_session_decode(const char *val, int vallen TSRMLS_DC) /* {{{ */ |
|
32 +static int php_session_decode(const char *val, int vallen TSRMLS_DC) /* {{{ */ |
|
33 { |
|
34 if (!PS(serializer)) { |
|
35 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown session.serialize_handler. Failed to decode session object"); |
|
36 - return; |
|
37 + return FAILURE; |
|
38 } |
|
39 if (PS(serializer)->decode(val, vallen TSRMLS_CC) == FAILURE) { |
|
40 php_session_destroy(TSRMLS_C); |
|
41 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to decode session object. Session has been destroyed"); |
|
42 + return FAILURE; |
|
43 } |
|
44 + return SUCCESS; |
|
45 } |
|
46 /* }}} */ |
|
47 |
|
48 @@ -413,7 +415,7 @@ PHPAPI char *php_session_create_id(PS_CREATE_SID_ARGS) /* {{{ */ |
|
49 |
|
50 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The ini setting hash_bits_per_character is out of range (should be 4, 5, or 6) - using 4 for now"); |
|
51 } |
|
52 - |
|
53 + |
|
54 outid = emalloc((size_t)((digest_len + 2) * ((8.0f / PS(hash_bits_per_character)) + 0.5))); |
|
55 j = (int) (bin_to_readable((char *)digest, digest_len, outid, (char)PS(hash_bits_per_character)) - outid); |
|
56 efree(digest); |
|
57 @@ -855,8 +857,11 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) /* {{{ */ |
|
58 ALLOC_INIT_ZVAL(current); |
|
59 if (php_var_unserialize(¤t, (const unsigned char **) &p, (const unsigned char *) endptr, &var_hash TSRMLS_CC)) { |
|
60 php_set_session_var(name, namelen, current, &var_hash TSRMLS_CC); |
|
61 + } else { |
|
62 + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); |
|
63 + return FAILURE; |
|
64 } |
|
65 - zval_ptr_dtor(¤t); |
|
66 + var_push_dtor_no_addref(&var_hash, ¤t); |
|
67 } |
|
68 PS_ADD_VARL(name, namelen); |
|
69 efree(name); |
|
70 @@ -947,8 +952,13 @@ PS_SERIALIZER_DECODE_FUNC(php) /* {{{ */ |
|
71 ALLOC_INIT_ZVAL(current); |
|
72 if (php_var_unserialize(¤t, (const unsigned char **) &q, (const unsigned char *) endptr, &var_hash TSRMLS_CC)) { |
|
73 php_set_session_var(name, namelen, current, &var_hash TSRMLS_CC); |
|
74 + } else { |
|
75 + var_push_dtor_no_addref(&var_hash, ¤t); |
|
76 + efree(name); |
|
77 + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); |
|
78 + return FAILURE; |
|
79 } |
|
80 - zval_ptr_dtor(¤t); |
|
81 + var_push_dtor_no_addref(&var_hash, ¤t); |
|
82 } |
|
83 PS_ADD_VARL(name, namelen); |
|
84 skip: |
|
85 @@ -1744,7 +1754,7 @@ static PHP_FUNCTION(session_set_save_handler) |
|
86 } |
|
87 efree(name); |
|
88 } |
|
89 - |
|
90 + |
|
91 if (PS(mod) && PS(mod) != &ps_mod_user) { |
|
92 zend_alter_ini_entry("session.save_handler", sizeof("session.save_handler"), "user", sizeof("user")-1, PHP_INI_USER, PHP_INI_STAGE_RUNTIME); |
|
93 } |
|
94 @@ -1922,9 +1932,7 @@ static PHP_FUNCTION(session_decode) |
|
95 return; |
|
96 } |
|
97 |
|
98 - php_session_decode(str, str_len TSRMLS_CC); |
|
99 - |
|
100 - RETURN_TRUE; |
|
101 + RETVAL_BOOL(php_session_decode(str, str_len TSRMLS_CC) == SUCCESS); |
|
102 } |
|
103 /* }}} */ |
|
104 |
|
105 @@ -2516,12 +2524,12 @@ static int php_session_rfc1867_callback(unsigned int event, void *event_data, vo |
|
106 case MULTIPART_EVENT_FILE_START: { |
|
107 multipart_event_file_start *data = (multipart_event_file_start *) event_data; |
|
108 |
|
109 - /* Do nothing when $_POST["PHP_SESSION_UPLOAD_PROGRESS"] is not set |
|
110 + /* Do nothing when $_POST["PHP_SESSION_UPLOAD_PROGRESS"] is not set |
|
111 * or when we have no session id */ |
|
112 if (!Z_TYPE(progress->sid) || !progress->key.c) { |
|
113 break; |
|
114 } |
|
115 - |
|
116 + |
|
117 /* First FILE_START event, initializing data */ |
|
118 if (!progress->data) { |
|
119 |
|
120 @@ -2571,7 +2579,7 @@ static int php_session_rfc1867_callback(unsigned int event, void *event_data, vo |
|
121 add_assoc_zval_ex(progress->current_file, "bytes_processed", sizeof("bytes_processed"), progress->current_file_bytes_processed); |
|
122 |
|
123 add_next_index_zval(progress->files, progress->current_file); |
|
124 - |
|
125 + |
|
126 Z_LVAL_P(progress->post_bytes_processed) = data->post_bytes_processed; |
|
127 |
|
128 php_session_rfc1867_update(progress, 0 TSRMLS_CC); |
|
129 @@ -2583,7 +2591,7 @@ static int php_session_rfc1867_callback(unsigned int event, void *event_data, vo |
|
130 if (!Z_TYPE(progress->sid) || !progress->key.c) { |
|
131 break; |
|
132 } |
|
133 - |
|
134 + |
|
135 Z_LVAL_P(progress->current_file_bytes_processed) = data->offset + data->length; |
|
136 Z_LVAL_P(progress->post_bytes_processed) = data->post_bytes_processed; |
|
137 |
|
138 @@ -2596,7 +2604,7 @@ static int php_session_rfc1867_callback(unsigned int event, void *event_data, vo |
|
139 if (!Z_TYPE(progress->sid) || !progress->key.c) { |
|
140 break; |
|
141 } |
|
142 - |
|
143 + |
|
144 if (data->temp_filename) { |
|
145 add_assoc_string_ex(progress->current_file, "tmp_name", sizeof("tmp_name"), data->temp_filename, 1); |
|
146 } |
|
147 diff --git a/ext/session/tests/session_decode_error2.phpt b/ext/session/tests/session_decode_error2.phpt |
|
148 index 4160f87..515047b 100644 |
|
149 --- a/ext/session/tests/session_decode_error2.phpt |
|
150 +++ b/ext/session/tests/session_decode_error2.phpt |
|
151 @@ -53,563 +53,247 @@ array(0) { |
|
152 } |
|
153 |
|
154 -- Iteration 4 -- |
|
155 -bool(true) |
|
156 -array(1) { |
|
157 - ["foo"]=> |
|
158 - NULL |
|
159 + |
|
160 +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s/session_decode_error2.php on line %d |
|
161 +bool(false) |
|
162 +array(0) { |
|
163 } |
|
164 |
|
165 -- Iteration 5 -- |
|
166 -bool(true) |
|
167 -array(1) { |
|
168 - ["foo"]=> |
|
169 - NULL |
|
170 +bool(false) |
|
171 +array(0) { |
|
172 } |
|
173 |
|
174 -- Iteration 6 -- |
|
175 -bool(true) |
|
176 -array(1) { |
|
177 - ["foo"]=> |
|
178 - NULL |
|
179 +bool(false) |
|
180 +array(0) { |
|
181 } |
|
182 |
|
183 -- Iteration 7 -- |
|
184 -bool(true) |
|
185 -array(1) { |
|
186 - ["foo"]=> |
|
187 - NULL |
|
188 +bool(false) |
|
189 +array(0) { |
|
190 } |
|
191 |
|
192 -- Iteration 8 -- |
|
193 -bool(true) |
|
194 -array(1) { |
|
195 - ["foo"]=> |
|
196 - NULL |
|
197 +bool(false) |
|
198 +array(0) { |
|
199 } |
|
200 |
|
201 -- Iteration 9 -- |
|
202 -bool(true) |
|
203 -array(1) { |
|
204 - ["foo"]=> |
|
205 - NULL |
|
206 +bool(false) |
|
207 +array(0) { |
|
208 } |
|
209 |
|
210 -- Iteration 10 -- |
|
211 -bool(true) |
|
212 -array(1) { |
|
213 - ["foo"]=> |
|
214 - NULL |
|
215 +bool(false) |
|
216 +array(0) { |
|
217 } |
|
218 |
|
219 -- Iteration 11 -- |
|
220 -bool(true) |
|
221 -array(1) { |
|
222 - ["foo"]=> |
|
223 - NULL |
|
224 +bool(false) |
|
225 +array(0) { |
|
226 } |
|
227 |
|
228 -- Iteration 12 -- |
|
229 -bool(true) |
|
230 -array(1) { |
|
231 - ["foo"]=> |
|
232 - NULL |
|
233 +bool(false) |
|
234 +array(0) { |
|
235 } |
|
236 |
|
237 -- Iteration 13 -- |
|
238 -bool(true) |
|
239 -array(1) { |
|
240 - ["foo"]=> |
|
241 - NULL |
|
242 +bool(false) |
|
243 +array(0) { |
|
244 } |
|
245 |
|
246 -- Iteration 14 -- |
|
247 -bool(true) |
|
248 -array(1) { |
|
249 - ["foo"]=> |
|
250 - NULL |
|
251 +bool(false) |
|
252 +array(0) { |
|
253 } |
|
254 |
|
255 -- Iteration 15 -- |
|
256 -bool(true) |
|
257 -array(1) { |
|
258 - ["foo"]=> |
|
259 - NULL |
|
260 +bool(false) |
|
261 +array(0) { |
|
262 } |
|
263 |
|
264 -- Iteration 16 -- |
|
265 -bool(true) |
|
266 -array(1) { |
|
267 - ["foo"]=> |
|
268 - NULL |
|
269 +bool(false) |
|
270 +array(0) { |
|
271 } |
|
272 |
|
273 -- Iteration 17 -- |
|
274 -bool(true) |
|
275 -array(1) { |
|
276 - ["foo"]=> |
|
277 - NULL |
|
278 +bool(false) |
|
279 +array(0) { |
|
280 } |
|
281 |
|
282 -- Iteration 18 -- |
|
283 -bool(true) |
|
284 -array(1) { |
|
285 - ["foo"]=> |
|
286 - NULL |
|
287 +bool(false) |
|
288 +array(0) { |
|
289 } |
|
290 |
|
291 -- Iteration 19 -- |
|
292 -bool(true) |
|
293 -array(1) { |
|
294 - ["foo"]=> |
|
295 - NULL |
|
296 +bool(false) |
|
297 +array(0) { |
|
298 } |
|
299 |
|
300 -- Iteration 20 -- |
|
301 -bool(true) |
|
302 -array(1) { |
|
303 - ["foo"]=> |
|
304 - NULL |
|
305 +bool(false) |
|
306 +array(0) { |
|
307 } |
|
308 |
|
309 -- Iteration 21 -- |
|
310 -bool(true) |
|
311 -array(1) { |
|
312 - ["foo"]=> |
|
313 - NULL |
|
314 +bool(false) |
|
315 +array(0) { |
|
316 } |
|
317 |
|
318 -- Iteration 22 -- |
|
319 -bool(true) |
|
320 -array(1) { |
|
321 - ["foo"]=> |
|
322 - NULL |
|
323 +bool(false) |
|
324 +array(0) { |
|
325 } |
|
326 |
|
327 -- Iteration 23 -- |
|
328 -bool(true) |
|
329 -array(1) { |
|
330 - ["foo"]=> |
|
331 - NULL |
|
332 +bool(false) |
|
333 +array(0) { |
|
334 } |
|
335 |
|
336 -- Iteration 24 -- |
|
337 -bool(true) |
|
338 -array(1) { |
|
339 - ["foo"]=> |
|
340 - NULL |
|
341 +bool(false) |
|
342 +array(0) { |
|
343 } |
|
344 |
|
345 -- Iteration 25 -- |
|
346 -bool(true) |
|
347 -array(1) { |
|
348 - ["foo"]=> |
|
349 - NULL |
|
350 +bool(false) |
|
351 +array(0) { |
|
352 } |
|
353 |
|
354 -- Iteration 26 -- |
|
355 -bool(true) |
|
356 -array(1) { |
|
357 - ["foo"]=> |
|
358 - NULL |
|
359 +bool(false) |
|
360 +array(0) { |
|
361 } |
|
362 |
|
363 -- Iteration 27 -- |
|
364 -bool(true) |
|
365 -array(1) { |
|
366 - ["foo"]=> |
|
367 - NULL |
|
368 +bool(false) |
|
369 +array(0) { |
|
370 } |
|
371 |
|
372 -- Iteration 28 -- |
|
373 -bool(true) |
|
374 -array(1) { |
|
375 - ["foo"]=> |
|
376 - NULL |
|
377 +bool(false) |
|
378 +array(0) { |
|
379 } |
|
380 |
|
381 -- Iteration 29 -- |
|
382 -bool(true) |
|
383 -array(1) { |
|
384 - ["foo"]=> |
|
385 - NULL |
|
386 +bool(false) |
|
387 +array(0) { |
|
388 } |
|
389 |
|
390 -- Iteration 30 -- |
|
391 -bool(true) |
|
392 -array(1) { |
|
393 - ["foo"]=> |
|
394 - NULL |
|
395 +bool(false) |
|
396 +array(0) { |
|
397 } |
|
398 |
|
399 -- Iteration 31 -- |
|
400 -bool(true) |
|
401 -array(1) { |
|
402 - ["foo"]=> |
|
403 - NULL |
|
404 +bool(false) |
|
405 +array(0) { |
|
406 } |
|
407 |
|
408 -- Iteration 32 -- |
|
409 -bool(true) |
|
410 -array(1) { |
|
411 - ["foo"]=> |
|
412 - NULL |
|
413 +bool(false) |
|
414 +array(0) { |
|
415 } |
|
416 |
|
417 -- Iteration 33 -- |
|
418 -bool(true) |
|
419 -array(1) { |
|
420 - ["foo"]=> |
|
421 - NULL |
|
422 +bool(false) |
|
423 +array(0) { |
|
424 } |
|
425 |
|
426 -- Iteration 34 -- |
|
427 -bool(true) |
|
428 -array(1) { |
|
429 - ["foo"]=> |
|
430 - array(3) { |
|
431 - [0]=> |
|
432 - int(1) |
|
433 - [1]=> |
|
434 - int(2) |
|
435 - [2]=> |
|
436 - int(3) |
|
437 - } |
|
438 +bool(false) |
|
439 +array(0) { |
|
440 } |
|
441 |
|
442 -- Iteration 35 -- |
|
443 -bool(true) |
|
444 -array(1) { |
|
445 - ["foo"]=> |
|
446 - array(3) { |
|
447 - [0]=> |
|
448 - int(1) |
|
449 - [1]=> |
|
450 - int(2) |
|
451 - [2]=> |
|
452 - int(3) |
|
453 - } |
|
454 +bool(false) |
|
455 +array(0) { |
|
456 } |
|
457 |
|
458 -- Iteration 36 -- |
|
459 -bool(true) |
|
460 -array(1) { |
|
461 - ["foo"]=> |
|
462 - array(3) { |
|
463 - [0]=> |
|
464 - int(1) |
|
465 - [1]=> |
|
466 - int(2) |
|
467 - [2]=> |
|
468 - int(3) |
|
469 - } |
|
470 +bool(false) |
|
471 +array(0) { |
|
472 } |
|
473 |
|
474 -- Iteration 37 -- |
|
475 -bool(true) |
|
476 -array(1) { |
|
477 - ["foo"]=> |
|
478 - array(3) { |
|
479 - [0]=> |
|
480 - int(1) |
|
481 - [1]=> |
|
482 - int(2) |
|
483 - [2]=> |
|
484 - int(3) |
|
485 - } |
|
486 +bool(false) |
|
487 +array(0) { |
|
488 } |
|
489 |
|
490 -- Iteration 38 -- |
|
491 -bool(true) |
|
492 -array(1) { |
|
493 - ["foo"]=> |
|
494 - array(3) { |
|
495 - [0]=> |
|
496 - int(1) |
|
497 - [1]=> |
|
498 - int(2) |
|
499 - [2]=> |
|
500 - int(3) |
|
501 - } |
|
502 +bool(false) |
|
503 +array(0) { |
|
504 } |
|
505 |
|
506 -- Iteration 39 -- |
|
507 -bool(true) |
|
508 -array(2) { |
|
509 - ["foo"]=> |
|
510 - array(3) { |
|
511 - [0]=> |
|
512 - int(1) |
|
513 - [1]=> |
|
514 - int(2) |
|
515 - [2]=> |
|
516 - int(3) |
|
517 - } |
|
518 - ["guff"]=> |
|
519 - NULL |
|
520 +bool(false) |
|
521 +array(0) { |
|
522 } |
|
523 |
|
524 -- Iteration 40 -- |
|
525 -bool(true) |
|
526 -array(2) { |
|
527 - ["foo"]=> |
|
528 - array(3) { |
|
529 - [0]=> |
|
530 - int(1) |
|
531 - [1]=> |
|
532 - int(2) |
|
533 - [2]=> |
|
534 - int(3) |
|
535 - } |
|
536 - ["guff"]=> |
|
537 - NULL |
|
538 +bool(false) |
|
539 +array(0) { |
|
540 } |
|
541 |
|
542 -- Iteration 41 -- |
|
543 -bool(true) |
|
544 -array(2) { |
|
545 - ["foo"]=> |
|
546 - array(3) { |
|
547 - [0]=> |
|
548 - int(1) |
|
549 - [1]=> |
|
550 - int(2) |
|
551 - [2]=> |
|
552 - int(3) |
|
553 - } |
|
554 - ["guff"]=> |
|
555 - NULL |
|
556 +bool(false) |
|
557 +array(0) { |
|
558 } |
|
559 |
|
560 -- Iteration 42 -- |
|
561 -bool(true) |
|
562 -array(2) { |
|
563 - ["foo"]=> |
|
564 - array(3) { |
|
565 - [0]=> |
|
566 - int(1) |
|
567 - [1]=> |
|
568 - int(2) |
|
569 - [2]=> |
|
570 - int(3) |
|
571 - } |
|
572 - ["guff"]=> |
|
573 - NULL |
|
574 +bool(false) |
|
575 +array(0) { |
|
576 } |
|
577 |
|
578 -- Iteration 43 -- |
|
579 -bool(true) |
|
580 -array(2) { |
|
581 - ["foo"]=> |
|
582 - &array(3) { |
|
583 - [0]=> |
|
584 - int(1) |
|
585 - [1]=> |
|
586 - int(2) |
|
587 - [2]=> |
|
588 - int(3) |
|
589 - } |
|
590 - ["guff"]=> |
|
591 - &array(3) { |
|
592 - [0]=> |
|
593 - int(1) |
|
594 - [1]=> |
|
595 - int(2) |
|
596 - [2]=> |
|
597 - int(3) |
|
598 - } |
|
599 +bool(false) |
|
600 +array(0) { |
|
601 } |
|
602 |
|
603 -- Iteration 44 -- |
|
604 -bool(true) |
|
605 -array(2) { |
|
606 - ["foo"]=> |
|
607 - &array(3) { |
|
608 - [0]=> |
|
609 - int(1) |
|
610 - [1]=> |
|
611 - int(2) |
|
612 - [2]=> |
|
613 - int(3) |
|
614 - } |
|
615 - ["guff"]=> |
|
616 - &array(3) { |
|
617 - [0]=> |
|
618 - int(1) |
|
619 - [1]=> |
|
620 - int(2) |
|
621 - [2]=> |
|
622 - int(3) |
|
623 - } |
|
624 +bool(false) |
|
625 +array(0) { |
|
626 } |
|
627 |
|
628 -- Iteration 45 -- |
|
629 -bool(true) |
|
630 -array(2) { |
|
631 - ["foo"]=> |
|
632 - &array(3) { |
|
633 - [0]=> |
|
634 - int(1) |
|
635 - [1]=> |
|
636 - int(2) |
|
637 - [2]=> |
|
638 - int(3) |
|
639 - } |
|
640 - ["guff"]=> |
|
641 - &array(3) { |
|
642 - [0]=> |
|
643 - int(1) |
|
644 - [1]=> |
|
645 - int(2) |
|
646 - [2]=> |
|
647 - int(3) |
|
648 - } |
|
649 +bool(false) |
|
650 +array(0) { |
|
651 } |
|
652 |
|
653 -- Iteration 46 -- |
|
654 -bool(true) |
|
655 -array(2) { |
|
656 - ["foo"]=> |
|
657 - &array(3) { |
|
658 - [0]=> |
|
659 - int(1) |
|
660 - [1]=> |
|
661 - int(2) |
|
662 - [2]=> |
|
663 - int(3) |
|
664 - } |
|
665 - ["guff"]=> |
|
666 - &array(3) { |
|
667 - [0]=> |
|
668 - int(1) |
|
669 - [1]=> |
|
670 - int(2) |
|
671 - [2]=> |
|
672 - int(3) |
|
673 - } |
|
674 +bool(false) |
|
675 +array(0) { |
|
676 } |
|
677 |
|
678 -- Iteration 47 -- |
|
679 -bool(true) |
|
680 -array(2) { |
|
681 - ["foo"]=> |
|
682 - &array(3) { |
|
683 - [0]=> |
|
684 - int(1) |
|
685 - [1]=> |
|
686 - int(2) |
|
687 - [2]=> |
|
688 - int(3) |
|
689 - } |
|
690 - ["guff"]=> |
|
691 - &array(3) { |
|
692 - [0]=> |
|
693 - int(1) |
|
694 - [1]=> |
|
695 - int(2) |
|
696 - [2]=> |
|
697 - int(3) |
|
698 - } |
|
699 +bool(false) |
|
700 +array(0) { |
|
701 } |
|
702 |
|
703 -- Iteration 48 -- |
|
704 -bool(true) |
|
705 -array(3) { |
|
706 - ["foo"]=> |
|
707 - &array(3) { |
|
708 - [0]=> |
|
709 - int(1) |
|
710 - [1]=> |
|
711 - int(2) |
|
712 - [2]=> |
|
713 - int(3) |
|
714 - } |
|
715 - ["guff"]=> |
|
716 - &array(3) { |
|
717 - [0]=> |
|
718 - int(1) |
|
719 - [1]=> |
|
720 - int(2) |
|
721 - [2]=> |
|
722 - int(3) |
|
723 - } |
|
724 - ["blah"]=> |
|
725 - NULL |
|
726 +bool(false) |
|
727 +array(0) { |
|
728 } |
|
729 |
|
730 -- Iteration 49 -- |
|
731 -bool(true) |
|
732 -array(3) { |
|
733 - ["foo"]=> |
|
734 - &array(3) { |
|
735 - [0]=> |
|
736 - int(1) |
|
737 - [1]=> |
|
738 - int(2) |
|
739 - [2]=> |
|
740 - int(3) |
|
741 - } |
|
742 - ["guff"]=> |
|
743 - &array(3) { |
|
744 - [0]=> |
|
745 - int(1) |
|
746 - [1]=> |
|
747 - int(2) |
|
748 - [2]=> |
|
749 - int(3) |
|
750 - } |
|
751 - ["blah"]=> |
|
752 - NULL |
|
753 +bool(false) |
|
754 +array(0) { |
|
755 } |
|
756 |
|
757 -- Iteration 50 -- |
|
758 -bool(true) |
|
759 -array(3) { |
|
760 - ["foo"]=> |
|
761 - &array(3) { |
|
762 - [0]=> |
|
763 - int(1) |
|
764 - [1]=> |
|
765 - int(2) |
|
766 - [2]=> |
|
767 - int(3) |
|
768 - } |
|
769 - ["guff"]=> |
|
770 - &array(3) { |
|
771 - [0]=> |
|
772 - int(1) |
|
773 - [1]=> |
|
774 - int(2) |
|
775 - [2]=> |
|
776 - int(3) |
|
777 - } |
|
778 - ["blah"]=> |
|
779 - NULL |
|
780 +bool(false) |
|
781 +array(0) { |
|
782 } |
|
783 |
|
784 -- Iteration 51 -- |
|
785 -bool(true) |
|
786 -array(3) { |
|
787 - ["foo"]=> |
|
788 - &array(3) { |
|
789 - [0]=> |
|
790 - int(1) |
|
791 - [1]=> |
|
792 - int(2) |
|
793 - [2]=> |
|
794 - int(3) |
|
795 - } |
|
796 - ["guff"]=> |
|
797 - &array(3) { |
|
798 - [0]=> |
|
799 - int(1) |
|
800 - [1]=> |
|
801 - int(2) |
|
802 - [2]=> |
|
803 - int(3) |
|
804 - } |
|
805 - ["blah"]=> |
|
806 - NULL |
|
807 +bool(false) |
|
808 +array(0) { |
|
809 } |
|
810 -bool(true) |
|
811 -Done |
|
812 |
|
813 +Warning: session_destroy(): Trying to destroy uninitialized session in %s/session_decode_error2.php on line %d |
|
814 +bool(false) |
|
815 +Done |
|
816 diff --git a/ext/session/tests/session_decode_variation3.phpt b/ext/session/tests/session_decode_variation3.phpt |
|
817 index 4a6f768..0960531 100644 |
|
818 --- a/ext/session/tests/session_decode_variation3.phpt |
|
819 +++ b/ext/session/tests/session_decode_variation3.phpt |
|
820 @@ -49,7 +49,7 @@ array(3) { |
|
821 } |
|
822 |
|
823 Warning: session_decode(): Unknown session.serialize_handler. Failed to decode session object in %s on line %d |
|
824 -bool(true) |
|
825 +bool(false) |
|
826 array(3) { |
|
827 ["foo"]=> |
|
828 int(1234567890) |
|
829 diff --git a/ext/standard/tests/serialize/bug70219.phpt b/ext/standard/tests/serialize/bug70219.phpt |
|
830 new file mode 100644 |
|
831 index 0000000..84a059f |
|
832 --- /dev/null |
|
833 +++ b/ext/standard/tests/serialize/bug70219.phpt |
|
834 @@ -0,0 +1,38 @@ |
|
835 +--TEST-- |
|
836 +Bug #70219 Use after free vulnerability in session deserializer |
|
837 +--FILE-- |
|
838 +<?php |
|
839 +class obj implements Serializable { |
|
840 + var $data; |
|
841 + function serialize() { |
|
842 + return serialize($this->data); |
|
843 + } |
|
844 + function unserialize($data) { |
|
845 + session_start(); |
|
846 + session_decode($data); |
|
847 + } |
|
848 +} |
|
849 + |
|
850 +$inner = 'ryat|a:1:{i:0;a:1:{i:1;'; |
|
851 +$exploit = 'a:2:{i:0;C:3:"obj":'.strlen($inner).':{'.$inner.'}i:1;R:4;}'; |
|
852 + |
|
853 +$data = unserialize($exploit); |
|
854 + |
|
855 +for ($i = 0; $i < 5; $i++) { |
|
856 + $v[$i] = 'hi'.$i; |
|
857 +} |
|
858 + |
|
859 +var_dump($data); |
|
860 +?> |
|
861 +--EXPECTF-- |
|
862 +Warning: session_decode(): Failed to decode session object. Session has been destroyed in %s on line %d |
|
863 +array(2) { |
|
864 + [0]=> |
|
865 + object(obj)#%d (1) { |
|
866 + ["data"]=> |
|
867 + NULL |
|
868 + } |
|
869 + [1]=> |
|
870 + array(0) { |
|
871 + } |
|
872 +} |
|
873 --- php-5.6.8/ext/standard/var_unserializer.c 2015-09-09 14:31:56.690869522 -0700 |
|
874 +++ php-5.6.8/ext/standard/var_unserializer.c 2015-09-09 14:27:54.301672915 -0700 |
|
875 @@ -90,7 +90,13 @@ |
|
876 |
|
877 PHPAPI void var_push_dtor_no_addref(php_unserialize_data_t *var_hashx, zval **rval) |
|
878 { |
|
879 - var_entries *var_hash = (*var_hashx)->last_dtor; |
|
880 + var_entries *var_hash; |
|
881 + |
|
882 + if (!var_hashx || !*var_hashx) { |
|
883 + return; |
|
884 + } |
|
885 + |
|
886 + var_hash = (*var_hashx)->last_dtor; |
|
887 #if VAR_ENTRIES_DBG |
|
888 fprintf(stderr, "var_push_dtor_no_addref(%p, %ld): %d (%d)\n", *rval, var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval), Z_REFCOUNT_PP(rval)); |
|
889 #endif |
|
890 @@ -304,23 +310,19 @@ |
|
891 ALLOC_INIT_ZVAL(key); |
|
892 |
|
893 if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) { |
|
894 - zval_dtor(key); |
|
895 - FREE_ZVAL(key); |
|
896 - return 0; |
|
897 + var_push_dtor_no_addref(var_hash, &key); |
|
898 } |
|
899 |
|
900 if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) { |
|
901 - zval_dtor(key); |
|
902 - FREE_ZVAL(key); |
|
903 + var_push_dtor_no_addref(var_hash, &key); |
|
904 return 0; |
|
905 } |
|
906 |
|
907 ALLOC_INIT_ZVAL(data); |
|
908 |
|
909 if (!php_var_unserialize(&data, p, max, var_hash TSRMLS_CC)) { |
|
910 - zval_dtor(key); |
|
911 - FREE_ZVAL(key); |
|
912 - zval_ptr_dtor(&data); |
|
913 + var_push_dtor_no_addref(var_hash, &key); |
|
914 + var_push_dtor_no_addref(var_hash, &data); |
|
915 return 0; |
|
916 } |
|
917 |
|
918 @@ -349,9 +351,7 @@ |
|
919 sizeof data, NULL); |
|
920 } |
|
921 var_push_dtor(var_hash, &data); |
|
922 - |
|
923 - zval_dtor(key); |
|
924 - FREE_ZVAL(key); |
|
925 + var_push_dtor_no_addref(var_hash, &key); |
|
926 |
|
927 if (elements && *(*p-1) != ';' && *(*p-1) != '}') { |
|
928 (*p)--; |
|
929 --- php-5.6.8/ext/standard/var_unserializer.re 2015-09-09 14:31:56.691428583 -0700 |
|
930 +++ php-5.6.8/ext/standard/var_unserializer.re 2015-09-09 14:29:28.764247264 -0700 |
|
931 @@ -89,7 +89,13 @@ |
|
932 |
|
933 PHPAPI void var_push_dtor_no_addref(php_unserialize_data_t *var_hashx, zval **rval) |
|
934 { |
|
935 - var_entries *var_hash = (*var_hashx)->last_dtor; |
|
936 + var_entries *var_hash; |
|
937 + |
|
938 + if (!var_hashx || !*var_hashx) { |
|
939 + return; |
|
940 + } |
|
941 + |
|
942 + var_hash = (*var_hashx)->last_dtor; |
|
943 #if VAR_ENTRIES_DBG |
|
944 fprintf(stderr, "var_push_dtor_no_addref(%p, %ld): %d (%d)\n", *rval, var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval), Z_REFCOUNT_PP(rval)); |
|
945 #endif |
|
946 @@ -310,23 +316,20 @@ |
|
947 ALLOC_INIT_ZVAL(key); |
|
948 |
|
949 if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) { |
|
950 - zval_dtor(key); |
|
951 - FREE_ZVAL(key); |
|
952 + var_push_dtor_no_addref(var_hash, &key); |
|
953 return 0; |
|
954 } |
|
955 |
|
956 if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) { |
|
957 - zval_dtor(key); |
|
958 - FREE_ZVAL(key); |
|
959 + var_push_dtor_no_addref(var_hash, &key); |
|
960 return 0; |
|
961 } |
|
962 |
|
963 ALLOC_INIT_ZVAL(data); |
|
964 |
|
965 if (!php_var_unserialize(&data, p, max, var_hash TSRMLS_CC)) { |
|
966 - zval_dtor(key); |
|
967 - FREE_ZVAL(key); |
|
968 - zval_ptr_dtor(&data); |
|
969 + var_push_dtor_no_addref(var_hash, &key); |
|
970 + var_push_dtor_no_addref(var_hash, &data); |
|
971 return 0; |
|
972 } |
|
973 |
|
974 @@ -355,9 +358,7 @@ |
|
975 sizeof data, NULL); |
|
976 } |
|
977 var_push_dtor(var_hash, &data); |
|
978 - |
|
979 - zval_dtor(key); |
|
980 - FREE_ZVAL(key); |
|
981 + var_push_dtor_no_addref(var_hash, &key); |
|
982 |
|
983 if (elements && *(*p-1) != ';' && *(*p-1) != '}') { |
|
984 (*p)--; |