1/* 2 +----------------------------------------------------------------------+ 3 | PHP Version 7 | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1997-2017 The PHP Group | 6 +----------------------------------------------------------------------+ 7 | This source file is subject to version 3.01 of the PHP license, | 8 | that is bundled with this package in the file LICENSE, and is | 9 | available through the world-wide-web at the following url: | 10 | http://www.php.net/license/3_01.txt | 11 | If you did not receive a copy of the PHP license and are unable to | 12 | obtain it through the world-wide-web, please send a note to | 13 | license@php.net so we can mail you a copy immediately. | 14 +----------------------------------------------------------------------+ 15 | Author: Sascha Schumann <sascha@schumann.cx> | 16 +----------------------------------------------------------------------+ 17*/ 18 19/* $Id$ */ 20 21#include "php.h" 22#include "ext/standard/php_var.h" 23#include "php_incomplete_class.h" 24 25/* {{{ reference-handling for unserializer: var_* */ 26#define VAR_ENTRIES_MAX 1024 27#define VAR_ENTRIES_DBG 0 28 29/* VAR_FLAG used in var_dtor entries to signify an entry on which __wakeup should be called */ 30#define VAR_WAKEUP_FLAG 1 31 32typedef struct { 33 zval *data[VAR_ENTRIES_MAX]; 34 zend_long used_slots; 35 void *next; 36} var_entries; 37 38typedef struct { 39 zval data[VAR_ENTRIES_MAX]; 40 zend_long used_slots; 41 void *next; 42} var_dtor_entries; 43 44static inline void var_push(php_unserialize_data_t *var_hashx, zval *rval) 45{ 46 var_entries *var_hash = (*var_hashx)->last; 47#if VAR_ENTRIES_DBG 48 fprintf(stderr, "var_push(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_P(rval)); 49#endif 50 51 if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) { 52 var_hash = emalloc(sizeof(var_entries)); 53 var_hash->used_slots = 0; 54 var_hash->next = 0; 55 56 if (!(*var_hashx)->first) { 57 (*var_hashx)->first = var_hash; 58 } else { 59 ((var_entries *) (*var_hashx)->last)->next = var_hash; 60 } 61 62 (*var_hashx)->last = var_hash; 63 } 64 65 var_hash->data[var_hash->used_slots++] = rval; 66} 67 68PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval *rval) 69{ 70 zval *tmp_var = var_tmp_var(var_hashx); 71 if (!tmp_var) { 72 return; 73 } 74 ZVAL_COPY(tmp_var, rval); 75} 76 77PHPAPI zval *var_tmp_var(php_unserialize_data_t *var_hashx) 78{ 79 var_dtor_entries *var_hash; 80 81 if (!var_hashx || !*var_hashx) { 82 return NULL; 83 } 84 85 var_hash = (*var_hashx)->last_dtor; 86 if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) { 87 var_hash = emalloc(sizeof(var_dtor_entries)); 88 var_hash->used_slots = 0; 89 var_hash->next = 0; 90 91 if (!(*var_hashx)->first_dtor) { 92 (*var_hashx)->first_dtor = var_hash; 93 } else { 94 ((var_dtor_entries *) (*var_hashx)->last_dtor)->next = var_hash; 95 } 96 97 (*var_hashx)->last_dtor = var_hash; 98 } 99 ZVAL_UNDEF(&var_hash->data[var_hash->used_slots]); 100 Z_VAR_FLAGS(var_hash->data[var_hash->used_slots]) = 0; 101 return &var_hash->data[var_hash->used_slots++]; 102} 103 104PHPAPI void var_replace(php_unserialize_data_t *var_hashx, zval *ozval, zval *nzval) 105{ 106 zend_long i; 107 var_entries *var_hash = (*var_hashx)->first; 108#if VAR_ENTRIES_DBG 109 fprintf(stderr, "var_replace(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_P(nzval)); 110#endif 111 112 while (var_hash) { 113 for (i = 0; i < var_hash->used_slots; i++) { 114 if (var_hash->data[i] == ozval) { 115 var_hash->data[i] = nzval; 116 /* do not break here */ 117 } 118 } 119 var_hash = var_hash->next; 120 } 121} 122 123static zval *var_access(php_unserialize_data_t *var_hashx, zend_long id) 124{ 125 var_entries *var_hash = (*var_hashx)->first; 126#if VAR_ENTRIES_DBG 127 fprintf(stderr, "var_access(%ld): %ld\n", var_hash?var_hash->used_slots:-1L, id); 128#endif 129 130 while (id >= VAR_ENTRIES_MAX && var_hash && var_hash->used_slots == VAR_ENTRIES_MAX) { 131 var_hash = var_hash->next; 132 id -= VAR_ENTRIES_MAX; 133 } 134 135 if (!var_hash) return NULL; 136 137 if (id < 0 || id >= var_hash->used_slots) return NULL; 138 139 return var_hash->data[id]; 140} 141 142PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) 143{ 144 void *next; 145 zend_long i; 146 var_entries *var_hash = (*var_hashx)->first; 147 var_dtor_entries *var_dtor_hash = (*var_hashx)->first_dtor; 148 zend_bool wakeup_failed = 0; 149 zval wakeup_name; 150 ZVAL_UNDEF(&wakeup_name); 151 152#if VAR_ENTRIES_DBG 153 fprintf(stderr, "var_destroy(%ld)\n", var_hash?var_hash->used_slots:-1L); 154#endif 155 156 while (var_hash) { 157 next = var_hash->next; 158 efree_size(var_hash, sizeof(var_entries)); 159 var_hash = next; 160 } 161 162 while (var_dtor_hash) { 163 for (i = 0; i < var_dtor_hash->used_slots; i++) { 164 zval *zv = &var_dtor_hash->data[i]; 165#if VAR_ENTRIES_DBG 166 fprintf(stderr, "var_destroy dtor(%p, %ld)\n", var_dtor_hash->data[i], Z_REFCOUNT_P(var_dtor_hash->data[i])); 167#endif 168 169 /* Perform delayed __wakeup calls */ 170 if (Z_VAR_FLAGS_P(zv) == VAR_WAKEUP_FLAG) { 171 if (!wakeup_failed) { 172 zval retval; 173 if (Z_ISUNDEF(wakeup_name)) { 174 ZVAL_STRINGL(&wakeup_name, "__wakeup", sizeof("__wakeup") - 1); 175 } 176 177 BG(serialize_lock)++; 178 if (call_user_function_ex(CG(function_table), zv, &wakeup_name, &retval, 0, 0, 1, NULL) == FAILURE || Z_ISUNDEF(retval)) { 179 wakeup_failed = 1; 180 GC_FLAGS(Z_OBJ_P(zv)) |= IS_OBJ_DESTRUCTOR_CALLED; 181 } 182 BG(serialize_lock)--; 183 184 zval_ptr_dtor(&retval); 185 } else { 186 GC_FLAGS(Z_OBJ_P(zv)) |= IS_OBJ_DESTRUCTOR_CALLED; 187 } 188 } 189 190 zval_ptr_dtor(zv); 191 } 192 next = var_dtor_hash->next; 193 efree_size(var_dtor_hash, sizeof(var_dtor_entries)); 194 var_dtor_hash = next; 195 } 196 197 zval_ptr_dtor(&wakeup_name); 198} 199 200/* }}} */ 201 202static zend_string *unserialize_str(const unsigned char **p, size_t len, size_t maxlen) 203{ 204 size_t i, j; 205 zend_string *str = zend_string_safe_alloc(1, len, 0, 0); 206 unsigned char *end = *(unsigned char **)p+maxlen; 207 208 if (end < *p) { 209 zend_string_free(str); 210 return NULL; 211 } 212 213 for (i = 0; i < len; i++) { 214 if (*p >= end) { 215 zend_string_free(str); 216 return NULL; 217 } 218 if (**p != '\\') { 219 ZSTR_VAL(str)[i] = (char)**p; 220 } else { 221 unsigned char ch = 0; 222 223 for (j = 0; j < 2; j++) { 224 (*p)++; 225 if (**p >= '0' && **p <= '9') { 226 ch = (ch << 4) + (**p -'0'); 227 } else if (**p >= 'a' && **p <= 'f') { 228 ch = (ch << 4) + (**p -'a'+10); 229 } else if (**p >= 'A' && **p <= 'F') { 230 ch = (ch << 4) + (**p -'A'+10); 231 } else { 232 zend_string_free(str); 233 return NULL; 234 } 235 } 236 ZSTR_VAL(str)[i] = (char)ch; 237 } 238 (*p)++; 239 } 240 ZSTR_VAL(str)[i] = 0; 241 ZSTR_LEN(str) = i; 242 return str; 243} 244 245static inline int unserialize_allowed_class(zend_string *class_name, HashTable *classes) 246{ 247 zend_string *lcname; 248 int res; 249 ALLOCA_FLAG(use_heap) 250 251 if(classes == NULL) { 252 return 1; 253 } 254 if(!zend_hash_num_elements(classes)) { 255 return 0; 256 } 257 258 ZSTR_ALLOCA_ALLOC(lcname, ZSTR_LEN(class_name), use_heap); 259 zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(class_name), ZSTR_LEN(class_name)); 260 res = zend_hash_exists(classes, lcname); 261 ZSTR_ALLOCA_FREE(lcname, use_heap); 262 return res; 263} 264 265#define YYFILL(n) do { } while (0) 266#define YYCTYPE unsigned char 267#define YYCURSOR cursor 268#define YYLIMIT limit 269#define YYMARKER marker 270 271 272/*!re2c 273uiv = [+]? [0-9]+; 274iv = [+-]? [0-9]+; 275nv = [+-]? ([0-9]* "." [0-9]+|[0-9]+ "." [0-9]*); 276nvexp = (iv | nv) [eE] [+-]? iv; 277any = [\000-\377]; 278object = [OC]; 279*/ 280 281 282 283static inline zend_long parse_iv2(const unsigned char *p, const unsigned char **q) 284{ 285 char cursor; 286 zend_long result = 0; 287 int neg = 0; 288 289 switch (*p) { 290 case '-': 291 neg++; 292 /* fall-through */ 293 case '+': 294 p++; 295 } 296 297 while (1) { 298 cursor = (char)*p; 299 if (cursor >= '0' && cursor <= '9') { 300 result = result * 10 + (size_t)(cursor - (unsigned char)'0'); 301 } else { 302 break; 303 } 304 p++; 305 } 306 if (q) *q = p; 307 if (neg) return -result; 308 return result; 309} 310 311static inline zend_long parse_iv(const unsigned char *p) 312{ 313 return parse_iv2(p, NULL); 314} 315 316/* no need to check for length - re2c already did */ 317static inline size_t parse_uiv(const unsigned char *p) 318{ 319 unsigned char cursor; 320 size_t result = 0; 321 322 if (*p == '+') { 323 p++; 324 } 325 326 while (1) { 327 cursor = *p; 328 if (cursor >= '0' && cursor <= '9') { 329 result = result * 10 + (size_t)(cursor - (unsigned char)'0'); 330 } else { 331 break; 332 } 333 p++; 334 } 335 return result; 336} 337 338#define UNSERIALIZE_PARAMETER zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash, HashTable *classes 339#define UNSERIALIZE_PASSTHRU rval, p, max, var_hash, classes 340 341static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER); 342 343static zend_always_inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, int objprops) 344{ 345 while (elements-- > 0) { 346 zval key, *data, d, *old_data; 347 zend_ulong idx; 348 349 ZVAL_UNDEF(&key); 350 351 if (!php_var_unserialize_internal(&key, p, max, NULL, classes)) { 352 zval_dtor(&key); 353 return 0; 354 } 355 356 data = NULL; 357 ZVAL_UNDEF(&d); 358 359 if (!objprops) { 360 if (Z_TYPE(key) == IS_LONG) { 361 idx = Z_LVAL(key); 362numeric_key: 363 if (UNEXPECTED((old_data = zend_hash_index_find(ht, idx)) != NULL)) { 364 //??? update hash 365 var_push_dtor(var_hash, old_data); 366 data = zend_hash_index_update(ht, idx, &d); 367 } else { 368 data = zend_hash_index_add_new(ht, idx, &d); 369 } 370 } else if (Z_TYPE(key) == IS_STRING) { 371 if (UNEXPECTED(ZEND_HANDLE_NUMERIC(Z_STR(key), idx))) { 372 goto numeric_key; 373 } 374 if (UNEXPECTED((old_data = zend_hash_find(ht, Z_STR(key))) != NULL)) { 375 //??? update hash 376 var_push_dtor(var_hash, old_data); 377 data = zend_hash_update(ht, Z_STR(key), &d); 378 } else { 379 data = zend_hash_add_new(ht, Z_STR(key), &d); 380 } 381 } else { 382 zval_dtor(&key); 383 return 0; 384 } 385 } else { 386 if (EXPECTED(Z_TYPE(key) == IS_STRING)) { 387string_key: 388 if ((old_data = zend_hash_find(ht, Z_STR(key))) != NULL) { 389 if (Z_TYPE_P(old_data) == IS_INDIRECT) { 390 old_data = Z_INDIRECT_P(old_data); 391 } 392 var_push_dtor(var_hash, old_data); 393 data = zend_hash_update_ind(ht, Z_STR(key), &d); 394 } else { 395 data = zend_hash_add_new(ht, Z_STR(key), &d); 396 } 397 } else if (Z_TYPE(key) == IS_LONG) { 398 /* object properties should include no integers */ 399 convert_to_string(&key); 400 goto string_key; 401 } else { 402 zval_dtor(&key); 403 return 0; 404 } 405 } 406 407 if (!php_var_unserialize_internal(data, p, max, var_hash, classes)) { 408 zval_dtor(&key); 409 return 0; 410 } 411 412 var_push_dtor(var_hash, data); 413 zval_dtor(&key); 414 415 if (elements && *(*p-1) != ';' && *(*p-1) != '}') { 416 (*p)--; 417 return 0; 418 } 419 } 420 421 return 1; 422} 423 424static inline int finish_nested_data(UNSERIALIZE_PARAMETER) 425{ 426 if (*p >= max || **p != '}') { 427 return 0; 428 } 429 430 (*p)++; 431 return 1; 432} 433 434static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce) 435{ 436 zend_long datalen; 437 438 datalen = parse_iv2((*p) + 2, p); 439 440 (*p) += 2; 441 442 if (datalen < 0 || (max - (*p)) <= datalen) { 443 zend_error(E_WARNING, "Insufficient data for unserializing - %pd required, %pd present", datalen, (zend_long)(max - (*p))); 444 return 0; 445 } 446 447 if (ce->unserialize == NULL) { 448 zend_error(E_WARNING, "Class %s has no unserializer", ZSTR_VAL(ce->name)); 449 object_init_ex(rval, ce); 450 } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash) != SUCCESS) { 451 return 0; 452 } 453 454 (*p) += datalen; 455 456 return finish_nested_data(UNSERIALIZE_PASSTHRU); 457} 458 459static inline zend_long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce) 460{ 461 zend_long elements; 462 463 if( *p >= max - 2) { 464 zend_error(E_WARNING, "Bad unserialize data"); 465 return -1; 466 } 467 468 elements = parse_iv2((*p) + 2, p); 469 470 (*p) += 2; 471 472 if (ce->serialize == NULL) { 473 object_init_ex(rval, ce); 474 } else { 475 /* If this class implements Serializable, it should not land here but in object_custom(). The passed string 476 obviously doesn't descend from the regular serializer. */ 477 zend_error(E_WARNING, "Erroneous data format for unserializing '%s'", ZSTR_VAL(ce->name)); 478 return -1; 479 } 480 481 return elements; 482} 483 484#ifdef PHP_WIN32 485# pragma optimize("", off) 486#endif 487static inline int object_common2(UNSERIALIZE_PARAMETER, zend_long elements) 488{ 489 HashTable *ht; 490 zend_bool has_wakeup; 491 492 if (Z_TYPE_P(rval) != IS_OBJECT) { 493 return 0; 494 } 495 496 has_wakeup = Z_OBJCE_P(rval) != PHP_IC_ENTRY 497 && zend_hash_str_exists(&Z_OBJCE_P(rval)->function_table, "__wakeup", sizeof("__wakeup")-1); 498 499 ht = Z_OBJPROP_P(rval); 500 if (elements >= HT_MAX_SIZE - zend_hash_num_elements(ht)) { 501 return 0; 502 } 503 504 zend_hash_extend(ht, zend_hash_num_elements(ht) + elements, (ht->u.flags & HASH_FLAG_PACKED)); 505 if (!process_nested_data(UNSERIALIZE_PASSTHRU, ht, elements, 1)) { 506 if (has_wakeup) { 507 ZVAL_DEREF(rval); 508 GC_FLAGS(Z_OBJ_P(rval)) |= IS_OBJ_DESTRUCTOR_CALLED; 509 } 510 return 0; 511 } 512 513 ZVAL_DEREF(rval); 514 if (has_wakeup) { 515 /* Delay __wakeup call until end of serialization */ 516 zval *wakeup_var = var_tmp_var(var_hash); 517 ZVAL_COPY(wakeup_var, rval); 518 Z_VAR_FLAGS_P(wakeup_var) = VAR_WAKEUP_FLAG; 519 } 520 521 return finish_nested_data(UNSERIALIZE_PASSTHRU); 522} 523#ifdef PHP_WIN32 524# pragma optimize("", on) 525#endif 526 527PHPAPI int php_var_unserialize(zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash) 528{ 529 HashTable *classes = NULL; 530 return php_var_unserialize_ex(UNSERIALIZE_PASSTHRU); 531} 532 533PHPAPI int php_var_unserialize_ex(UNSERIALIZE_PARAMETER) 534{ 535 var_entries *orig_var_entries = (*var_hash)->last; 536 zend_long orig_used_slots = orig_var_entries ? orig_var_entries->used_slots : 0; 537 int result; 538 539 result = php_var_unserialize_internal(UNSERIALIZE_PASSTHRU); 540 541 if (!result) { 542 /* If the unserialization failed, mark all elements that have been added to var_hash 543 * as NULL. This will forbid their use by other unserialize() calls in the same 544 * unserialization context. */ 545 var_entries *e = orig_var_entries; 546 zend_long s = orig_used_slots; 547 while (e) { 548 for (; s < e->used_slots; s++) { 549 e->data[s] = NULL; 550 } 551 552 e = e->next; 553 s = 0; 554 } 555 } 556 557 return result; 558} 559 560static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER) 561{ 562 const unsigned char *cursor, *limit, *marker, *start; 563 zval *rval_ref; 564 565 limit = max; 566 cursor = *p; 567 568 if (YYCURSOR >= YYLIMIT) { 569 return 0; 570 } 571 572 if (var_hash && (*p)[0] != 'R') { 573 var_push(var_hash, rval); 574 } 575 576 start = cursor; 577 578/*!re2c 579 580"R:" iv ";" { 581 zend_long id; 582 583 *p = YYCURSOR; 584 if (!var_hash) return 0; 585 586 id = parse_iv(start + 2) - 1; 587 if (id == -1 || (rval_ref = var_access(var_hash, id)) == NULL) { 588 return 0; 589 } 590 591 if (Z_ISUNDEF_P(rval_ref) || (Z_ISREF_P(rval_ref) && Z_ISUNDEF_P(Z_REFVAL_P(rval_ref)))) { 592 return 0; 593 } 594 595 if (Z_ISREF_P(rval_ref)) { 596 ZVAL_COPY(rval, rval_ref); 597 } else { 598 ZVAL_NEW_REF(rval_ref, rval_ref); 599 ZVAL_COPY(rval, rval_ref); 600 } 601 602 return 1; 603} 604 605"r:" iv ";" { 606 zend_long id; 607 608 *p = YYCURSOR; 609 if (!var_hash) return 0; 610 611 id = parse_iv(start + 2) - 1; 612 if (id == -1 || (rval_ref = var_access(var_hash, id)) == NULL) { 613 return 0; 614 } 615 616 if (rval_ref == rval) { 617 return 0; 618 } 619 620 if (Z_ISUNDEF_P(rval_ref) || (Z_ISREF_P(rval_ref) && Z_ISUNDEF_P(Z_REFVAL_P(rval_ref)))) { 621 return 0; 622 } 623 624 ZVAL_COPY(rval, rval_ref); 625 626 return 1; 627} 628 629"N;" { 630 *p = YYCURSOR; 631 ZVAL_NULL(rval); 632 return 1; 633} 634 635"b:" [01] ";" { 636 *p = YYCURSOR; 637 ZVAL_BOOL(rval, parse_iv(start + 2)); 638 return 1; 639} 640 641"i:" iv ";" { 642#if SIZEOF_ZEND_LONG == 4 643 int digits = YYCURSOR - start - 3; 644 645 if (start[2] == '-' || start[2] == '+') { 646 digits--; 647 } 648 649 /* Use double for large zend_long values that were serialized on a 64-bit system */ 650 if (digits >= MAX_LENGTH_OF_LONG - 1) { 651 if (digits == MAX_LENGTH_OF_LONG - 1) { 652 int cmp = strncmp((char*)YYCURSOR - MAX_LENGTH_OF_LONG, long_min_digits, MAX_LENGTH_OF_LONG - 1); 653 654 if (!(cmp < 0 || (cmp == 0 && start[2] == '-'))) { 655 goto use_double; 656 } 657 } else { 658 goto use_double; 659 } 660 } 661#endif 662 *p = YYCURSOR; 663 ZVAL_LONG(rval, parse_iv(start + 2)); 664 return 1; 665} 666 667"d:" ("NAN" | "-"? "INF") ";" { 668 *p = YYCURSOR; 669 670 if (!strncmp((char*)start + 2, "NAN", 3)) { 671 ZVAL_DOUBLE(rval, php_get_nan()); 672 } else if (!strncmp((char*)start + 2, "INF", 3)) { 673 ZVAL_DOUBLE(rval, php_get_inf()); 674 } else if (!strncmp((char*)start + 2, "-INF", 4)) { 675 ZVAL_DOUBLE(rval, -php_get_inf()); 676 } else { 677 ZVAL_NULL(rval); 678 } 679 680 return 1; 681} 682 683"d:" (iv | nv | nvexp) ";" { 684#if SIZEOF_ZEND_LONG == 4 685use_double: 686#endif 687 *p = YYCURSOR; 688 ZVAL_DOUBLE(rval, zend_strtod((const char *)start + 2, NULL)); 689 return 1; 690} 691 692"s:" uiv ":" ["] { 693 size_t len, maxlen; 694 char *str; 695 696 len = parse_uiv(start + 2); 697 maxlen = max - YYCURSOR; 698 if (maxlen < len) { 699 *p = start + 2; 700 return 0; 701 } 702 703 str = (char*)YYCURSOR; 704 705 YYCURSOR += len; 706 707 if (*(YYCURSOR) != '"') { 708 *p = YYCURSOR; 709 return 0; 710 } 711 712 if (*(YYCURSOR + 1) != ';') { 713 *p = YYCURSOR + 1; 714 return 0; 715 } 716 717 YYCURSOR += 2; 718 *p = YYCURSOR; 719 720 ZVAL_STRINGL(rval, str, len); 721 return 1; 722} 723 724"S:" uiv ":" ["] { 725 size_t len, maxlen; 726 zend_string *str; 727 728 len = parse_uiv(start + 2); 729 maxlen = max - YYCURSOR; 730 if (maxlen < len) { 731 *p = start + 2; 732 return 0; 733 } 734 735 if ((str = unserialize_str(&YYCURSOR, len, maxlen)) == NULL) { 736 return 0; 737 } 738 739 if (*(YYCURSOR) != '"') { 740 zend_string_free(str); 741 *p = YYCURSOR; 742 return 0; 743 } 744 745 if (*(YYCURSOR + 1) != ';') { 746 efree(str); 747 *p = YYCURSOR + 1; 748 return 0; 749 } 750 751 YYCURSOR += 2; 752 *p = YYCURSOR; 753 754 ZVAL_STR(rval, str); 755 return 1; 756} 757 758"a:" uiv ":" "{" { 759 zend_long elements = parse_iv(start + 2); 760 /* use iv() not uiv() in order to check data range */ 761 *p = YYCURSOR; 762 if (!var_hash) return 0; 763 764 if (elements < 0 || elements >= HT_MAX_SIZE) { 765 return 0; 766 } 767 768 array_init_size(rval, elements); 769 if (elements) { 770 /* we can't convert from packed to hash during unserialization, because 771 reference to some zvals might be keept in var_hash (to support references) */ 772 zend_hash_real_init(Z_ARRVAL_P(rval), 0); 773 } 774 775 if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_P(rval), elements, 0)) { 776 return 0; 777 } 778 779 return finish_nested_data(UNSERIALIZE_PASSTHRU); 780} 781 782"o:" iv ":" ["] { 783 zend_long elements; 784 if (!var_hash) return 0; 785 786 elements = object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR); 787 if (elements < 0 || elements >= HT_MAX_SIZE) { 788 return 0; 789 } 790 return object_common2(UNSERIALIZE_PASSTHRU, elements); 791} 792 793object ":" uiv ":" ["] { 794 size_t len, len2, len3, maxlen; 795 zend_long elements; 796 char *str; 797 zend_string *class_name; 798 zend_class_entry *ce; 799 int incomplete_class = 0; 800 801 int custom_object = 0; 802 803 zval user_func; 804 zval retval; 805 zval args[1]; 806 807 if (!var_hash) return 0; 808 if (*start == 'C') { 809 custom_object = 1; 810 } 811 812 len2 = len = parse_uiv(start + 2); 813 maxlen = max - YYCURSOR; 814 if (maxlen < len || len == 0) { 815 *p = start + 2; 816 return 0; 817 } 818 819 str = (char*)YYCURSOR; 820 821 YYCURSOR += len; 822 823 if (*(YYCURSOR) != '"') { 824 *p = YYCURSOR; 825 return 0; 826 } 827 if (*(YYCURSOR+1) != ':') { 828 *p = YYCURSOR+1; 829 return 0; 830 } 831 832 len3 = strspn(str, "0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377\\"); 833 if (len3 != len) 834 { 835 *p = YYCURSOR + len3 - len; 836 return 0; 837 } 838 839 class_name = zend_string_init(str, len, 0); 840 841 do { 842 if(!unserialize_allowed_class(class_name, classes)) { 843 incomplete_class = 1; 844 ce = PHP_IC_ENTRY; 845 break; 846 } 847 848 /* Try to find class directly */ 849 BG(serialize_lock)++; 850 ce = zend_lookup_class(class_name); 851 if (ce) { 852 BG(serialize_lock)--; 853 if (EG(exception)) { 854 zend_string_release(class_name); 855 return 0; 856 } 857 break; 858 } 859 BG(serialize_lock)--; 860 861 if (EG(exception)) { 862 zend_string_release(class_name); 863 return 0; 864 } 865 866 /* Check for unserialize callback */ 867 if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) { 868 incomplete_class = 1; 869 ce = PHP_IC_ENTRY; 870 break; 871 } 872 873 /* Call unserialize callback */ 874 ZVAL_STRING(&user_func, PG(unserialize_callback_func)); 875 876 ZVAL_STR_COPY(&args[0], class_name); 877 BG(serialize_lock)++; 878 if (call_user_function_ex(CG(function_table), NULL, &user_func, &retval, 1, args, 0, NULL) != SUCCESS) { 879 BG(serialize_lock)--; 880 if (EG(exception)) { 881 zend_string_release(class_name); 882 zval_ptr_dtor(&user_func); 883 zval_ptr_dtor(&args[0]); 884 return 0; 885 } 886 php_error_docref(NULL, E_WARNING, "defined (%s) but not found", Z_STRVAL(user_func)); 887 incomplete_class = 1; 888 ce = PHP_IC_ENTRY; 889 zval_ptr_dtor(&user_func); 890 zval_ptr_dtor(&args[0]); 891 break; 892 } 893 BG(serialize_lock)--; 894 zval_ptr_dtor(&retval); 895 if (EG(exception)) { 896 zend_string_release(class_name); 897 zval_ptr_dtor(&user_func); 898 zval_ptr_dtor(&args[0]); 899 return 0; 900 } 901 902 /* The callback function may have defined the class */ 903 BG(serialize_lock)++; 904 if ((ce = zend_lookup_class(class_name)) == NULL) { 905 php_error_docref(NULL, E_WARNING, "Function %s() hasn't defined the class it was called for", Z_STRVAL(user_func)); 906 incomplete_class = 1; 907 ce = PHP_IC_ENTRY; 908 } 909 BG(serialize_lock)--; 910 911 zval_ptr_dtor(&user_func); 912 zval_ptr_dtor(&args[0]); 913 break; 914 } while (1); 915 916 *p = YYCURSOR; 917 918 if (custom_object) { 919 int ret; 920 921 ret = object_custom(UNSERIALIZE_PASSTHRU, ce); 922 923 if (ret && incomplete_class) { 924 php_store_class_name(rval, ZSTR_VAL(class_name), len2); 925 } 926 zend_string_release(class_name); 927 return ret; 928 } 929 930 elements = object_common1(UNSERIALIZE_PASSTHRU, ce); 931 932 if (elements < 0) { 933 zend_string_release(class_name); 934 return 0; 935 } 936 937 if (incomplete_class) { 938 php_store_class_name(rval, ZSTR_VAL(class_name), len2); 939 } 940 zend_string_release(class_name); 941 942 return object_common2(UNSERIALIZE_PASSTHRU, elements); 943} 944 945"}" { 946 /* this is the case where we have less data than planned */ 947 php_error_docref(NULL, E_NOTICE, "Unexpected end of serialized data"); 948 return 0; /* not sure if it should be 0 or 1 here? */ 949} 950 951any { return 0; } 952 953*/ 954 955 return 0; 956} 957