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