1diff -u libmagic.orig/apprentice.c libmagic/apprentice.c 2--- libmagic.orig/apprentice.c 2023-07-17 16:38:35.000000000 +0200 3+++ libmagic/apprentice.c 2024-02-15 19:28:46.036308654 +0100 4@@ -48,7 +48,9 @@ 5 #ifdef QUICK 6 #include <sys/mman.h> 7 #endif 8+#ifdef HAVE_DIRENT_H 9 #include <dirent.h> 10+#endif 11 #include <limits.h> 12 #ifdef HAVE_BYTESWAP_H 13 #include <byteswap.h> 14@@ -146,10 +148,7 @@ 15 #endif 16 17 file_private char *mkdbname(struct magic_set *, const char *, int); 18-file_private struct magic_map *apprentice_buf(struct magic_set *, struct magic *, 19- size_t); 20 file_private struct magic_map *apprentice_map(struct magic_set *, const char *); 21-file_private int check_buffer(struct magic_set *, struct magic_map *, const char *); 22 file_private void apprentice_unmap(struct magic_map *); 23 file_private int apprentice_compile(struct magic_set *, struct magic_map *, 24 const char *); 25@@ -185,6 +184,8 @@ 26 { NULL, 0, NULL } 27 }; 28 29+#include "../data_file.c" 30+ 31 #ifdef COMPILE_ONLY 32 33 int main(int, char *[]); 34@@ -445,21 +446,13 @@ 35 struct mlist *ml; 36 37 mlp->map = NULL; 38- if ((ml = CAST(struct mlist *, malloc(sizeof(*ml)))) == NULL) 39+ if ((ml = CAST(struct mlist *, emalloc(sizeof(*ml)))) == NULL) 40 return -1; 41 42 ml->map = idx == 0 ? map : NULL; 43 ml->magic = map->magic[idx]; 44 ml->nmagic = map->nmagic[idx]; 45- if (ml->nmagic) { 46- ml->magic_rxcomp = CAST(file_regex_t **, 47- calloc(ml->nmagic, sizeof(*ml->magic_rxcomp))); 48- if (ml->magic_rxcomp == NULL) { 49- free(ml); 50- return -1; 51- } 52- } else 53- ml->magic_rxcomp = NULL; 54+ 55 mlp->prev->next = ml; 56 ml->prev = mlp->prev; 57 ml->next = mlp; 58@@ -537,13 +530,19 @@ 59 return; 60 for (i = 0; i < MAGIC_SETS; i++) 61 mlist_free(ms->mlist[i]); 62- free(ms->o.pbuf); 63- free(ms->o.buf); 64- free(ms->c.li); 65+ if (ms->o.pbuf) { 66+ efree(ms->o.pbuf); 67+ } 68+ if (ms->o.buf) { 69+ efree(ms->o.buf); 70+ } 71+ if (ms->c.li) { 72+ efree(ms->c.li); 73+ } 74 #ifdef USE_C_LOCALE 75 freelocale(ms->c_lc_ctype); 76 #endif 77- free(ms); 78+ efree(ms); 79 } 80 81 file_protected struct magic_set * 82@@ -552,7 +551,7 @@ 83 struct magic_set *ms; 84 size_t i, len; 85 86- if ((ms = CAST(struct magic_set *, calloc(CAST(size_t, 1u), 87+ if ((ms = CAST(struct magic_set *, ecalloc(CAST(size_t, 1u), 88 sizeof(*ms)))) == NULL) 89 return NULL; 90 91@@ -565,7 +564,7 @@ 92 ms->o.blen = 0; 93 len = (ms->c.len = 10) * sizeof(*ms->c.li); 94 95- if ((ms->c.li = CAST(struct level_info *, malloc(len))) == NULL) 96+ if ((ms->c.li = CAST(struct level_info *, emalloc(len))) == NULL) 97 goto free; 98 99 ms->event_flags = 0; 100@@ -589,49 +588,35 @@ 101 #endif 102 return ms; 103 free: 104- free(ms); 105+ efree(ms); 106 return NULL; 107 } 108 109 file_private void 110 apprentice_unmap(struct magic_map *map) 111 { 112- size_t i; 113- char *p; 114 if (map == NULL) 115 return; 116- 117- switch (map->type) { 118- case MAP_TYPE_USER: 119- break; 120- case MAP_TYPE_MALLOC: 121- p = CAST(char *, map->p); 122- for (i = 0; i < MAGIC_SETS; i++) { 123- char *b = RCAST(char *, map->magic[i]); 124- if (p != NULL && b >= p && b <= p + map->len) 125- continue; 126- free(b); 127+ if (map->p != php_magic_database) { 128+ if (map->p == NULL) { 129+ int j; 130+ for (j = 0; j < MAGIC_SETS; j++) { 131+ if (map->magic[j]) { 132+ efree(map->magic[j]); 133+ } 134+ } 135+ } else { 136+ efree(map->p); 137 } 138- free(p); 139- break; 140-#ifdef QUICK 141- case MAP_TYPE_MMAP: 142- if (map->p && map->p != MAP_FAILED) 143- (void)munmap(map->p, map->len); 144- break; 145-#endif 146- default: 147- fprintf(stderr, "Bad map type %d", map->type); 148- abort(); 149 } 150- free(map); 151+ efree(map); 152 } 153 154 file_private struct mlist * 155 mlist_alloc(void) 156 { 157 struct mlist *mlist; 158- if ((mlist = CAST(struct mlist *, calloc(1, sizeof(*mlist)))) == NULL) { 159+ if ((mlist = CAST(struct mlist *, ecalloc(1, sizeof(*mlist)))) == NULL) { 160 return NULL; 161 } 162 mlist->next = mlist->prev = mlist; 163@@ -652,21 +637,9 @@ 164 file_private void 165 mlist_free_one(struct mlist *ml) 166 { 167- size_t i; 168- 169 if (ml->map) 170 apprentice_unmap(CAST(struct magic_map *, ml->map)); 171- 172- for (i = 0; i < ml->nmagic; ++i) { 173- if (ml->magic_rxcomp[i]) { 174- file_regfree(ml->magic_rxcomp[i]); 175- free(ml->magic_rxcomp[i]); 176- ml->magic_rxcomp[i] = NULL; 177- } 178- } 179- free(ml->magic_rxcomp); 180- ml->magic_rxcomp = NULL; 181- free(ml); 182+ efree(ml); 183 } 184 185 file_private void 186@@ -685,50 +658,6 @@ 187 mlist_free_one(mlist); 188 } 189 190-#ifndef COMPILE_ONLY 191-/* void **bufs: an array of compiled magic files */ 192-file_protected int 193-buffer_apprentice(struct magic_set *ms, struct magic **bufs, 194- size_t *sizes, size_t nbufs) 195-{ 196- size_t i, j; 197- struct magic_map *map; 198- 199- if (nbufs == 0) 200- return -1; 201- 202- (void)file_reset(ms, 0); 203- 204- init_file_tables(); 205- 206- for (i = 0; i < MAGIC_SETS; i++) { 207- mlist_free(ms->mlist[i]); 208- if ((ms->mlist[i] = mlist_alloc()) == NULL) { 209- file_oomem(ms, sizeof(*ms->mlist[0])); 210- goto fail; 211- } 212- } 213- 214- for (i = 0; i < nbufs; i++) { 215- map = apprentice_buf(ms, bufs[i], sizes[i]); 216- if (map == NULL) 217- goto fail; 218- 219- for (j = 0; j < MAGIC_SETS; j++) { 220- if (add_mlist(ms->mlist[j], map, j) == -1) { 221- file_oomem(ms, sizeof(*ms->mlist[0])); 222- goto fail; 223- } 224- } 225- } 226- 227- return 0; 228-fail: 229- mlist_free_all(ms); 230- return -1; 231-} 232-#endif 233- 234 /* const char *fn: list of magic files and directories */ 235 file_protected int 236 file_apprentice(struct magic_set *ms, const char *fn, int action) 237@@ -739,12 +668,28 @@ 238 239 (void)file_reset(ms, 0); 240 241+/* XXX disabling default magic loading so the compiled in data is used */ 242+#if 0 243 if ((fn = magic_getpath(fn, action)) == NULL) 244 return -1; 245+#endif 246 247 init_file_tables(); 248 249- if ((mfn = strdup(fn)) == NULL) { 250+ if (fn == NULL) 251+ fn = getenv("MAGIC"); 252+ if (fn == NULL) { 253+ for (i = 0; i < MAGIC_SETS; i++) { 254+ mlist_free(ms->mlist[i]); 255+ if ((ms->mlist[i] = mlist_alloc()) == NULL) { 256+ file_oomem(ms, sizeof(*ms->mlist[i])); 257+ return -1; 258+ } 259+ } 260+ return apprentice_1(ms, fn, action); 261+ } 262+ 263+ if ((mfn = estrdup(fn)) == NULL) { 264 file_oomem(ms, strlen(fn)); 265 return -1; 266 } 267@@ -757,7 +702,7 @@ 268 mlist_free(ms->mlist[j]); 269 ms->mlist[j] = NULL; 270 } 271- free(mfn); 272+ efree(mfn); 273 return -1; 274 } 275 } 276@@ -774,7 +719,7 @@ 277 fn = p; 278 } 279 280- free(mfn); 281+ efree(mfn); 282 283 if (errs == -1) { 284 for (i = 0; i < MAGIC_SETS; i++) { 285@@ -1289,7 +1234,7 @@ 286 287 size_t incr = mset[i].max + ALLOC_INCR; 288 if ((mp = CAST(struct magic_entry *, 289- realloc(mset[i].me, sizeof(*mp) * incr))) == 290+ erealloc(mset[i].me, sizeof(*mp) * incr))) == 291 NULL) { 292 file_oomem(ms, sizeof(*mp) * incr); 293 return -1; 294@@ -1312,13 +1257,19 @@ 295 load_1(struct magic_set *ms, int action, const char *fn, int *errs, 296 struct magic_entry_set *mset) 297 { 298- size_t lineno = 0, llen = 0; 299+ char buffer[BUFSIZ + 1]; 300 char *line = NULL; 301- ssize_t len; 302+ size_t len; 303+ size_t lineno = 0; 304 struct magic_entry me; 305 306- FILE *f = fopen(ms->file = fn, "r"); 307- if (f == NULL) { 308+ php_stream *stream; 309+ 310+ 311+ ms->file = fn; 312+ stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS, NULL); 313+ 314+ if (stream == NULL) { 315 if (errno != ENOENT) 316 file_error(ms, errno, "cannot read magic file `%s'", 317 fn); 318@@ -1328,8 +1279,7 @@ 319 320 memset(&me, 0, sizeof(me)); 321 /* read and parse this file */ 322- for (ms->line = 1; (len = getline(&line, &llen, f)) != -1; 323- ms->line++) { 324+ for (ms->line = 1; (line = php_stream_get_line(stream, buffer , BUFSIZ, &len)) != NULL; ms->line++) { 325 if (len == 0) /* null line, garbage, etc */ 326 continue; 327 if (line[len - 1] == '\n') { 328@@ -1388,8 +1338,8 @@ 329 } 330 if (me.mp) 331 (void)addentry(ms, &me, mset); 332- free(line); 333- (void)fclose(f); 334+ efree(line); 335+ php_stream_close(stream); 336 } 337 338 /* 339@@ -1474,7 +1424,7 @@ 340 } 341 342 slen = sizeof(**ma) * mentrycount; 343- if ((*ma = CAST(struct magic *, malloc(slen))) == NULL) { 344+ if ((*ma = CAST(struct magic *, emalloc(slen))) == NULL) { 345 file_oomem(ms, slen); 346 return -1; 347 } 348@@ -1496,8 +1446,8 @@ 349 if (me == NULL) 350 return; 351 for (i = 0; i < nme; i++) 352- free(me[i].mp); 353- free(me); 354+ efree(me[i].mp); 355+ efree(me); 356 } 357 358 file_private struct magic_map * 359@@ -1506,18 +1456,19 @@ 360 int errs = 0; 361 uint32_t i, j; 362 size_t files = 0, maxfiles = 0; 363- char **filearr = NULL, *mfn; 364- struct stat st; 365+ char **filearr = NULL; 366+ zend_stat_t st = {0}; 367 struct magic_map *map; 368 struct magic_entry_set mset[MAGIC_SETS]; 369- DIR *dir; 370- struct dirent *d; 371+ php_stream *dir; 372+ php_stream_dirent d; 373+ 374 375 memset(mset, 0, sizeof(mset)); 376 ms->flags |= MAGIC_CHECK; /* Enable checks for parsed files */ 377 378 379- if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) 380+ if ((map = CAST(struct magic_map *, ecalloc(1, sizeof(*map)))) == NULL) 381 { 382 file_oomem(ms, sizeof(*map)); 383 return NULL; 384@@ -1529,52 +1480,50 @@ 385 (void)fprintf(stderr, "%s\n", usg_hdr); 386 387 /* load directory or file */ 388- if (stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) { 389- dir = opendir(fn); 390+ /* FIXME: Read file names and sort them to prevent 391+ non-determinism. See Debian bug #488562. */ 392+ if (php_sys_stat(fn, &st) == 0 && S_ISDIR(st.st_mode)) { 393+ int mflen; 394+ char mfn[MAXPATHLEN]; 395+ 396+ dir = php_stream_opendir((char *)fn, REPORT_ERRORS, NULL); 397 if (!dir) { 398 errs++; 399 goto out; 400 } 401- while ((d = readdir(dir)) != NULL) { 402- if (d->d_name[0] == '.') 403- continue; 404- if (asprintf(&mfn, "%s/%s", fn, d->d_name) < 0) { 405+ while (php_stream_readdir(dir, &d)) { 406+ if ((mflen = snprintf(mfn, sizeof(mfn), "%s/%s", fn, d.d_name)) < 0) { 407 file_oomem(ms, 408- strlen(fn) + strlen(d->d_name) + 2); 409+ strlen(fn) + strlen(d.d_name) + 2); 410 errs++; 411- closedir(dir); 412+ php_stream_closedir(dir); 413 goto out; 414 } 415- if (stat(mfn, &st) == -1 || !S_ISREG(st.st_mode)) { 416- free(mfn); 417+ if (zend_stat(mfn, &st) == -1 || !S_ISREG(st.st_mode)) { 418 continue; 419 } 420 if (files >= maxfiles) { 421 size_t mlen; 422- char **nfilearr; 423 maxfiles = (maxfiles + 1) * 2; 424 mlen = maxfiles * sizeof(*filearr); 425- if ((nfilearr = CAST(char **, 426- realloc(filearr, mlen))) == NULL) { 427+ if ((filearr = CAST(char **, 428+ erealloc(filearr, mlen))) == NULL) { 429 file_oomem(ms, mlen); 430- free(mfn); 431- closedir(dir); 432+ php_stream_closedir(dir); 433 errs++; 434 goto out; 435 } 436- filearr = nfilearr; 437 } 438- filearr[files++] = mfn; 439+ filearr[files++] = estrndup(mfn, (mflen > sizeof(mfn) - 1)? sizeof(mfn) - 1: mflen); 440 } 441- closedir(dir); 442+ php_stream_closedir(dir); 443 if (filearr) { 444 qsort(filearr, files, sizeof(*filearr), cmpstrp); 445 for (i = 0; i < files; i++) { 446 load_1(ms, action, filearr[i], &errs, mset); 447- free(filearr[i]); 448+ efree(filearr[i]); 449 } 450- free(filearr); 451- filearr = NULL; 452+ efree(filearr); 453 } 454 } else 455 load_1(ms, action, fn, &errs, mset); 456@@ -1612,7 +1561,6 @@ 457 } 458 459 out: 460- free(filearr); 461 for (j = 0; j < MAGIC_SETS; j++) 462 magic_entry_free(mset[j].me, mset[j].count); 463 464@@ -2060,7 +2008,7 @@ 465 if (me->cont_count == me->max_count) { 466 struct magic *nm; 467 size_t cnt = me->max_count + ALLOC_CHUNK; 468- if ((nm = CAST(struct magic *, realloc(me->mp, 469+ if ((nm = CAST(struct magic *, erealloc(me->mp, 470 sizeof(*nm) * cnt))) == NULL) { 471 file_oomem(ms, sizeof(*nm) * cnt); 472 return -1; 473@@ -2075,7 +2023,7 @@ 474 static const size_t len = sizeof(*m) * ALLOC_CHUNK; 475 if (me->mp != NULL) 476 return 1; 477- if ((m = CAST(struct magic *, malloc(len))) == NULL) { 478+ if ((m = CAST(struct magic *, emalloc(len))) == NULL) { 479 file_oomem(ms, len); 480 return -1; 481 } 482@@ -2301,7 +2249,7 @@ 483 484 m->mask_op = 0; 485 if (*l == '~') { 486- if (!IS_STRING(m->type)) 487+ if (!IS_LIBMAGIC_STRING(m->type)) 488 m->mask_op |= FILE_OPINVERSE; 489 else if (ms->flags & MAGIC_CHECK) 490 file_magwarn(ms, "'~' invalid for string types"); 491@@ -2310,7 +2258,7 @@ 492 m->str_range = 0; 493 m->str_flags = m->type == FILE_PSTRING ? PSTRING_1_LE : 0; 494 if ((op = get_op(*l)) != -1) { 495- if (IS_STRING(m->type)) { 496+ if (IS_LIBMAGIC_STRING(m->type)) { 497 int r; 498 499 if (op != FILE_OPDIVIDE) { 500@@ -2497,7 +2445,7 @@ 501 502 file_private int 503 parse_extra(struct magic_set *ms, struct magic_entry *me, const char *line, 504- size_t llen, off_t off, size_t len, const char *name, const char *extra, 505+ size_t llen, zend_off_t off, size_t len, const char *name, const char *extra, 506 int nt) 507 { 508 size_t i; 509@@ -2860,13 +2808,19 @@ 510 return -1; 511 } 512 if (m->type == FILE_REGEX) { 513- file_regex_t rx; 514- int rc = 515- file_regcomp(ms, &rx, m->value.s, REG_EXTENDED); 516- if (rc == 0) { 517- file_regfree(&rx); 518+ zend_string *pattern; 519+ int options = 0; 520+ pcre_cache_entry *pce; 521+ 522+ pattern = convert_libmagic_pattern(m->value.s, strlen(m->value.s), options); 523+ 524+ if ((pce = pcre_get_compiled_regex_cache(pattern)) == NULL) { 525+ zend_string_release(pattern); 526+ return -1; 527 } 528- return rc ? -1 : 0; 529+ zend_string_release(pattern); 530+ 531+ return 0; 532 } 533 return 0; 534 default: 535@@ -3245,120 +3199,83 @@ 536 } 537 538 /* 539- * handle a buffer containing a compiled file. 540- */ 541-file_private struct magic_map * 542-apprentice_buf(struct magic_set *ms, struct magic *buf, size_t len) 543-{ 544- struct magic_map *map; 545- 546- if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) { 547- file_oomem(ms, sizeof(*map)); 548- return NULL; 549- } 550- map->len = len; 551- map->p = buf; 552- map->type = MAP_TYPE_USER; 553- if (check_buffer(ms, map, "buffer") != 0) { 554- apprentice_unmap(map); 555- return NULL; 556- } 557- return map; 558-} 559- 560-/* 561 * handle a compiled file. 562 */ 563 564 file_private struct magic_map * 565 apprentice_map(struct magic_set *ms, const char *fn) 566 { 567- int fd; 568- struct stat st; 569+ uint32_t *ptr; 570+ uint32_t version, entries = 0, nentries; 571+ int needsbyteswap; 572 char *dbname = NULL; 573 struct magic_map *map; 574- struct magic_map *rv = NULL; 575+ size_t i; 576+ php_stream *stream = NULL; 577+ php_stream_statbuf st; 578+ 579+ 580 581- fd = -1; 582- if ((map = CAST(struct magic_map *, calloc(1, sizeof(*map)))) == NULL) { 583+ if ((map = CAST(struct magic_map *, ecalloc(1, sizeof(*map)))) == NULL) { 584 file_oomem(ms, sizeof(*map)); 585- goto error; 586+ return NULL; 587 } 588- map->type = MAP_TYPE_USER; /* unspecified */ 589+ 590+ if (fn == NULL) { 591+ map->p = (void *)&php_magic_database; 592+ goto internal_loaded; 593+ } 594+ 595+#ifdef PHP_WIN32 596+ /* Don't bother on windows with php_stream_open_wrapper, 597+ return to give apprentice_load() a chance. */ 598+ if (php_stream_stat_path_ex((char *)fn, 0, &st, NULL) == SUCCESS) { 599+ if (st.sb.st_mode & S_IFDIR) { 600+ goto error; 601+ } 602+ } 603+#endif 604 605 dbname = mkdbname(ms, fn, 0); 606 if (dbname == NULL) 607 goto error; 608 609- if ((fd = open(dbname, O_RDONLY|O_BINARY)) == -1) 610+ stream = php_stream_open_wrapper((char *)fn, "rb", REPORT_ERRORS, NULL); 611+ 612+ if (!stream) { 613 goto error; 614+ } 615 616- if (fstat(fd, &st) == -1) { 617+#ifndef PHP_WIN32 618+ if (php_stream_stat(stream, &st) < 0) { 619 file_error(ms, errno, "cannot stat `%s'", dbname); 620 goto error; 621 } 622- if (st.st_size < 8 || st.st_size > maxoff_t()) { 623+#endif 624+ if (st.sb.st_size < 8 || st.sb.st_size > maxoff_t()) { 625 file_error(ms, 0, "file `%s' is too %s", dbname, 626- st.st_size < 8 ? "small" : "large"); 627+ st.sb.st_size < 8 ? "small" : "large"); 628 goto error; 629 } 630 631- map->len = CAST(size_t, st.st_size); 632-#ifdef QUICK 633- map->type = MAP_TYPE_MMAP; 634- if ((map->p = mmap(0, CAST(size_t, st.st_size), PROT_READ|PROT_WRITE, 635- MAP_PRIVATE|MAP_FILE, fd, CAST(off_t, 0))) == MAP_FAILED) { 636- file_error(ms, errno, "cannot map `%s'", dbname); 637- goto error; 638- } 639-#else 640 map->type = MAP_TYPE_MALLOC; 641- if ((map->p = CAST(void *, malloc(map->len))) == NULL) { 642- file_oomem(ms, map->len); 643- goto error; 644- } 645- if (read(fd, map->p, map->len) != (ssize_t)map->len) { 646- file_badread(ms); 647- goto error; 648- } 649-#endif 650- (void)close(fd); 651- fd = -1; 652+ map->len = CAST(size_t, st.sb.st_size); 653+ map->p = CAST(void *, emalloc(map->len)); 654 655- if (check_buffer(ms, map, dbname) != 0) { 656- goto error; 657- } 658-#ifdef QUICK 659- if (mprotect(map->p, CAST(size_t, st.st_size), PROT_READ) == -1) { 660- file_error(ms, errno, "cannot mprotect `%s'", dbname); 661+ if (php_stream_read(stream, map->p, (size_t)st.sb.st_size) != (size_t)st.sb.st_size) { 662+ file_badread(ms); 663 goto error; 664 } 665-#endif 666- 667- free(dbname); 668- return map; 669- 670-error: 671- if (fd != -1) 672- (void)close(fd); 673- apprentice_unmap(map); 674- free(dbname); 675- return rv; 676-} 677 678-file_private int 679-check_buffer(struct magic_set *ms, struct magic_map *map, const char *dbname) 680-{ 681- uint32_t *ptr; 682- uint32_t entries, nentries; 683- uint32_t version; 684- int i, needsbyteswap; 685+ php_stream_close(stream); 686+ stream = NULL; 687 688- ptr = CAST(uint32_t *, map->p); 689+internal_loaded: 690+ ptr = (uint32_t *)(void *)map->p; 691 if (*ptr != MAGICNO) { 692 if (swap4(*ptr) != MAGICNO) { 693 file_error(ms, 0, "bad magic in `%s'", dbname); 694- return -1; 695+ goto error; 696 } 697 needsbyteswap = 1; 698 } else 699@@ -3368,17 +3285,29 @@ 700 else 701 version = ptr[1]; 702 if (version != VERSIONNO) { 703- file_error(ms, 0, "File %s supports only version %d magic " 704- "files. `%s' is version %d", VERSION, 705+ file_error(ms, 0, "File %d supports only version %d magic " 706+ "files. `%s' is version %d", MAGIC_VERSION, 707 VERSIONNO, dbname, version); 708- return -1; 709+ goto error; 710 } 711- entries = CAST(uint32_t, map->len / sizeof(struct magic)); 712- if ((entries * sizeof(struct magic)) != map->len) { 713- file_error(ms, 0, "Size of `%s' %" SIZE_T_FORMAT "u is not " 714- "a multiple of %" SIZE_T_FORMAT "u", 715- dbname, map->len, sizeof(struct magic)); 716- return -1; 717+ 718+ /* php_magic_database is a const, performing writes will segfault. This is for big-endian 719+ machines only, PPC and Sparc specifically. Consider static variable or MINIT in 720+ future. */ 721+ if (needsbyteswap && fn == NULL) { 722+ map->p = emalloc(sizeof(php_magic_database)); 723+ map->p = memcpy(map->p, php_magic_database, sizeof(php_magic_database)); 724+ } 725+ 726+ if (NULL != fn) { 727+ nentries = (uint32_t)(st.sb.st_size / sizeof(struct magic)); 728+ entries = (uint32_t)(st.sb.st_size / sizeof(struct magic)); 729+ if ((zend_off_t)(entries * sizeof(struct magic)) != st.sb.st_size) { 730+ file_error(ms, 0, "Size of `%s' %llu is not a multiple of %zu", 731+ dbname, (unsigned long long)st.sb.st_size, 732+ sizeof(struct magic)); 733+ goto error; 734+ } 735 } 736 map->magic[0] = CAST(struct magic *, map->p) + 1; 737 nentries = 0; 738@@ -3391,15 +3320,29 @@ 739 map->magic[i + 1] = map->magic[i] + map->nmagic[i]; 740 nentries += map->nmagic[i]; 741 } 742- if (entries != nentries + 1) { 743+ if (NULL != fn && entries != nentries + 1) { 744 file_error(ms, 0, "Inconsistent entries in `%s' %u != %u", 745 dbname, entries, nentries + 1); 746- return -1; 747+ goto error; 748 } 749 if (needsbyteswap) 750 for (i = 0; i < MAGIC_SETS; i++) 751 byteswap(map->magic[i], map->nmagic[i]); 752- return 0; 753+ 754+ if (dbname) { 755+ efree(dbname); 756+ } 757+ return map; 758+ 759+error: 760+ if (stream) { 761+ php_stream_close(stream); 762+ } 763+ apprentice_unmap(map); 764+ if (dbname) { 765+ efree(dbname); 766+ } 767+ return NULL; 768 } 769 770 /* 771@@ -3410,7 +3353,7 @@ 772 { 773 static const size_t nm = sizeof(*map->nmagic) * MAGIC_SETS; 774 static const size_t m = sizeof(**map->magic); 775- int fd = -1; 776+ php_stream *stream; 777 size_t len; 778 char *dbname; 779 int rv = -1; 780@@ -3425,8 +3368,10 @@ 781 if (dbname == NULL) 782 goto out; 783 784- if ((fd = open(dbname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)) == -1) 785- { 786+ /* wb+ == O_WRONLY|O_CREAT|O_TRUNC|O_BINARY */ 787+ stream = php_stream_open_wrapper((char *)fn, "wb+", REPORT_ERRORS, NULL); 788+ 789+ if (!stream) { 790 file_error(ms, errno, "cannot open `%s'", dbname); 791 goto out; 792 } 793@@ -3435,26 +3380,25 @@ 794 hdr.h[1] = VERSIONNO; 795 memcpy(hdr.h + 2, map->nmagic, nm); 796 797- if (write(fd, &hdr, sizeof(hdr)) != CAST(ssize_t, sizeof(hdr))) { 798+ if (php_stream_write(stream,(const char *)&hdr, sizeof(hdr)) != (ssize_t)sizeof(hdr)) { 799 file_error(ms, errno, "error writing `%s'", dbname); 800- goto out2; 801+ goto out; 802 } 803 804 for (i = 0; i < MAGIC_SETS; i++) { 805 len = m * map->nmagic[i]; 806- if (write(fd, map->magic[i], len) != CAST(ssize_t, len)) { 807+ if (php_stream_write(stream, (const char *)map->magic[i], len) != (ssize_t)len) { 808 file_error(ms, errno, "error writing `%s'", dbname); 809- goto out2; 810+ goto out; 811 } 812 } 813 814 rv = 0; 815-out2: 816- if (fd != -1) 817- (void)close(fd); 818+ if (stream) { 819+ php_stream_close(stream); 820+ } 821 out: 822- apprentice_unmap(map); 823- free(dbname); 824+ efree(dbname); 825 return rv; 826 } 827 828@@ -3488,17 +3432,18 @@ 829 q++; 830 /* Compatibility with old code that looked in .mime */ 831 if (ms->flags & MAGIC_MIME) { 832- if (asprintf(&buf, "%.*s.mime%s", CAST(int, q - fn), fn, ext) 833- < 0) 834- return NULL; 835- if (access(buf, R_OK) != -1) { 836+ spprintf(&buf, MAXPATHLEN, "%.*s.mime%s", CAST(int, q - fn), fn, ext); 837+#ifdef PHP_WIN32 838+ if (VCWD_ACCESS(buf, R_OK) == 0) { 839+#else 840+ if (VCWD_ACCESS(buf, R_OK) != -1) { 841+#endif 842 ms->flags &= MAGIC_MIME_TYPE; 843 return buf; 844 } 845- free(buf); 846+ efree(buf); 847 } 848- if (asprintf(&buf, "%.*s%s", CAST(int, q - fn), fn, ext) < 0) 849- return NULL; 850+ spprintf(&buf, MAXPATHLEN, "%.*s%s", CAST(int, q - fn), fn, ext); 851 852 /* Compatibility with old code that looked in .mime */ 853 if (strstr(fn, ".mime") != NULL) 854@@ -3620,7 +3565,7 @@ 855 m->offset = swap4(CAST(uint32_t, m->offset)); 856 m->in_offset = swap4(CAST(uint32_t, m->in_offset)); 857 m->lineno = swap4(CAST(uint32_t, m->lineno)); 858- if (IS_STRING(m->type)) { 859+ if (IS_LIBMAGIC_STRING(m->type)) { 860 m->str_range = swap4(m->str_range); 861 m->str_flags = swap4(m->str_flags); 862 } 863@@ -3717,7 +3662,6 @@ 864 continue; 865 if (strcmp(ma[i].value.s, name) == 0) { 866 v->magic = &ma[i]; 867- v->magic_rxcomp = &(ml->magic_rxcomp[i]); 868 for (j = i + 1; j < ml->nmagic; j++) 869 if (ma[j].cont_level == 0) 870 break; 871diff -u libmagic.orig/ascmagic.c libmagic/ascmagic.c 872--- libmagic.orig/ascmagic.c 2023-05-30 22:17:50.000000000 +0200 873+++ libmagic/ascmagic.c 2024-02-15 19:28:46.036308654 +0100 874@@ -96,7 +96,7 @@ 875 rv = file_ascmagic_with_encoding(ms, &bb, 876 ubuf, ulen, code, type, text); 877 878- free(ubuf); 879+ efree(ubuf); 880 881 return rv; 882 } 883@@ -143,7 +143,7 @@ 884 /* malloc size is a conservative overestimate; could be 885 improved, or at least realloced after conversion. */ 886 mlen = ulen * 6; 887- if ((utf8_buf = CAST(unsigned char *, malloc(mlen))) == NULL) { 888+ if ((utf8_buf = CAST(unsigned char *, emalloc(mlen))) == NULL) { 889 file_oomem(ms, mlen); 890 goto done; 891 } 892@@ -267,8 +267,8 @@ 893 goto done; 894 895 if (has_long_lines) 896- if (file_printf(ms, ", with very long lines (%" 897- SIZE_T_FORMAT "u)", has_long_lines) == -1) 898+ if (file_printf(ms, ", with very long lines (%zu)", 899+ has_long_lines) == -1) 900 goto done; 901 902 /* 903@@ -324,7 +324,8 @@ 904 } 905 rv = 1; 906 done: 907- free(utf8_buf); 908+ if (utf8_buf) 909+ efree(utf8_buf); 910 911 return rv; 912 } 913diff -u libmagic.orig/buffer.c libmagic/buffer.c 914--- libmagic.orig/buffer.c 2023-07-02 14:48:39.000000000 +0200 915+++ libmagic/buffer.c 2024-02-15 19:28:46.036308654 +0100 916@@ -31,19 +31,21 @@ 917 #endif /* lint */ 918 919 #include "magic.h" 920+#ifdef HAVE_UNISTD_H 921 #include <unistd.h> 922+#endif 923 #include <string.h> 924 #include <stdlib.h> 925 #include <sys/stat.h> 926 927 void 928-buffer_init(struct buffer *b, int fd, const struct stat *st, const void *data, 929+buffer_init(struct buffer *b, int fd, const zend_stat_t *st, const void *data, 930 size_t len) 931 { 932 b->fd = fd; 933 if (st) 934 memcpy(&b->st, st, sizeof(b->st)); 935- else if (b->fd == -1 || fstat(b->fd, &b->st) == -1) 936+ else if (b->fd == -1 || zend_fstat(b->fd, &b->st) == -1) 937 memset(&b->st, 0, sizeof(b->st)); 938 b->fbuf = data; 939 b->flen = len; 940@@ -55,7 +57,7 @@ 941 void 942 buffer_fini(struct buffer *b) 943 { 944- free(b->ebuf); 945+ efree(b->ebuf); 946 b->ebuf = NULL; 947 b->elen = 0; 948 } 949@@ -74,16 +76,18 @@ 950 b->elen = CAST(size_t, b->st.st_size) < b->flen ? 951 CAST(size_t, b->st.st_size) : b->flen; 952 if (b->elen == 0) { 953- free(b->ebuf); 954+ efree(b->ebuf); 955 b->ebuf = NULL; 956 return 0; 957 } 958- if ((b->ebuf = malloc(b->elen)) == NULL) 959+ if ((b->ebuf = emalloc(b->elen)) == NULL) 960 goto out; 961 962 b->eoff = b->st.st_size - b->elen; 963- if (pread(b->fd, b->ebuf, b->elen, b->eoff) == -1) { 964- free(b->ebuf); 965+ if (FINFO_LSEEK_FUNC(b->fd, b->eoff, SEEK_SET) == (zend_off_t)-1 || 966+ FINFO_READ_FUNC(b->fd, b->ebuf, b->elen) != (ssize_t)b->elen) 967+ { 968+ efree(b->ebuf); 969 b->ebuf = NULL; 970 goto out; 971 } 972diff -u libmagic.orig/cdf.c libmagic/cdf.c 973--- libmagic.orig/cdf.c 2022-09-24 22:56:49.000000000 +0200 974+++ libmagic/cdf.c 2024-02-15 19:28:46.036308654 +0100 975@@ -43,7 +43,9 @@ 976 #include <err.h> 977 #endif 978 #include <stdlib.h> 979+#ifdef HAVE_UNISTD_H 980 #include <unistd.h> 981+#endif 982 #include <string.h> 983 #include <time.h> 984 #include <ctype.h> 985@@ -91,44 +93,9 @@ 986 CDF_TOLE8(CAST(uint64_t, x)))) 987 #define CDF_GETUINT32(x, y) cdf_getuint32(x, y) 988 989-#define CDF_MALLOC(n) cdf_malloc(__FILE__, __LINE__, (n)) 990-#define CDF_REALLOC(p, n) cdf_realloc(__FILE__, __LINE__, (p), (n)) 991-#define CDF_CALLOC(n, u) cdf_calloc(__FILE__, __LINE__, (n), (u)) 992- 993- 994-/*ARGSUSED*/ 995-static void * 996-cdf_malloc(const char *file __attribute__((__unused__)), 997- size_t line __attribute__((__unused__)), size_t n) 998-{ 999- DPRINTF(("%s,%" SIZE_T_FORMAT "u: %s %" SIZE_T_FORMAT "u\n", 1000- file, line, __func__, n)); 1001- if (n == 0) 1002- n++; 1003- return malloc(n); 1004-} 1005- 1006-/*ARGSUSED*/ 1007-static void * 1008-cdf_realloc(const char *file __attribute__((__unused__)), 1009- size_t line __attribute__((__unused__)), void *p, size_t n) 1010-{ 1011- DPRINTF(("%s,%" SIZE_T_FORMAT "u: %s %" SIZE_T_FORMAT "u\n", 1012- file, line, __func__, n)); 1013- return realloc(p, n); 1014-} 1015- 1016-/*ARGSUSED*/ 1017-static void * 1018-cdf_calloc(const char *file __attribute__((__unused__)), 1019- size_t line __attribute__((__unused__)), size_t n, size_t u) 1020-{ 1021- DPRINTF(("%s,%" SIZE_T_FORMAT "u: %s %" SIZE_T_FORMAT "u %" 1022- SIZE_T_FORMAT "u\n", file, line, __func__, n, u)); 1023- if (n == 0) 1024- n++; 1025- return calloc(n, u); 1026-} 1027+#define CDF_MALLOC(n) emalloc(n) 1028+#define CDF_REALLOC(p, n) erealloc(p, n) 1029+#define CDF_CALLOC(n, u) ecalloc(n, u) 1030 1031 #if defined(HAVE_BYTESWAP_H) 1032 # define _cdf_tole2(x) bswap_16(x) 1033@@ -334,7 +301,7 @@ 1034 scn->sst_len = 0; 1035 scn->sst_dirlen = 0; 1036 scn->sst_ss = 0; 1037- free(scn->sst_tab); 1038+ efree(scn->sst_tab); 1039 scn->sst_tab = NULL; 1040 return -1; 1041 } 1042@@ -342,9 +309,11 @@ 1043 static size_t 1044 cdf_check_stream(const cdf_stream_t *sst, const cdf_header_t *h) 1045 { 1046+#ifndef NDEBUG 1047 size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ? 1048 CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h); 1049 assert(ss == sst->sst_ss); 1050+#endif 1051 return sst->sst_ss; 1052 } 1053 1054@@ -367,11 +336,11 @@ 1055 } 1056 1057 static ssize_t 1058-cdf_read(const cdf_info_t *info, off_t off, void *buf, size_t len) 1059+cdf_read(const cdf_info_t *info, zend_off_t off, void *buf, size_t len) 1060 { 1061 size_t siz = CAST(size_t, off + len); 1062 1063- if (CAST(off_t, off + len) != CAST(off_t, siz)) 1064+ if (CAST(zend_off_t, off + len) != CAST(zend_off_t, siz)) 1065 goto out; 1066 1067 if (info->i_buf != NULL && info->i_len >= siz) { 1068@@ -382,7 +351,10 @@ 1069 if (info->i_fd == -1) 1070 goto out; 1071 1072- if (pread(info->i_fd, buf, len, off) != CAST(ssize_t, len)) 1073+ if (FINFO_LSEEK_FUNC(info->i_fd, off, SEEK_SET) == (zend_off_t)-1) 1074+ return -1; 1075+ 1076+ if (FINFO_READ_FUNC(info->i_fd, buf, len) != (ssize_t)len) 1077 return -1; 1078 1079 return CAST(ssize_t, len); 1080@@ -397,7 +369,7 @@ 1081 char buf[512]; 1082 1083 (void)memcpy(cdf_bo.s, "\01\02\03\04", 4); 1084- if (cdf_read(info, CAST(off_t, 0), buf, sizeof(buf)) == -1) 1085+ if (cdf_read(info, CAST(zend_off_t, 0), buf, sizeof(buf)) == -1) 1086 return -1; 1087 cdf_unpack_header(h, buf); 1088 cdf_swap_header(h); 1089@@ -544,14 +516,14 @@ 1090 } 1091 out: 1092 sat->sat_len = i; 1093- free(msa); 1094+ efree(msa); 1095 return 0; 1096 out3: 1097 errno = EFTYPE; 1098 out2: 1099- free(msa); 1100+ efree(msa); 1101 out1: 1102- free(sat->sat_tab); 1103+ efree(sat->sat_tab); 1104 return -1; 1105 } 1106 1107@@ -719,7 +691,7 @@ 1108 return -1; 1109 1110 if ((buf = CAST(char *, CDF_MALLOC(ss))) == NULL) { 1111- free(dir->dir_tab); 1112+ efree(dir->dir_tab); 1113 return -1; 1114 } 1115 1116@@ -742,11 +714,11 @@ 1117 if (NEED_SWAP) 1118 for (i = 0; i < dir->dir_len; i++) 1119 cdf_swap_dir(&dir->dir_tab[i]); 1120- free(buf); 1121+ efree(buf); 1122 return 0; 1123 out: 1124- free(dir->dir_tab); 1125- free(buf); 1126+ efree(dir->dir_tab); 1127+ efree(buf); 1128 errno = EFTYPE; 1129 return -1; 1130 } 1131@@ -791,7 +763,7 @@ 1132 out: 1133 errno = EFTYPE; 1134 out1: 1135- free(ssat->sat_tab); 1136+ efree(ssat->sat_tab); 1137 return -1; 1138 } 1139 1140@@ -953,7 +925,7 @@ 1141 *maxcount = newcount; 1142 return inp; 1143 out: 1144- free(*info); 1145+ efree(*info); 1146 *maxcount = 0; 1147 *info = NULL; 1148 return NULL; 1149@@ -1136,7 +1108,7 @@ 1150 } 1151 return 0; 1152 out: 1153- free(*info); 1154+ efree(*info); 1155 *info = NULL; 1156 *count = 0; 1157 *maxcount = 0; 1158@@ -1428,7 +1400,7 @@ 1159 cdf_directory_t *d; 1160 char name[__arraycount(d->d_name)]; 1161 cdf_stream_t scn; 1162- struct timespec ts; 1163+ struct timeval ts; 1164 1165 static const char *types[] = { "empty", "user storage", 1166 "user stream", "lockbytes", "property", "root storage" }; 1167@@ -1470,7 +1442,7 @@ 1168 break; 1169 } 1170 cdf_dump_stream(&scn); 1171- free(scn.sst_tab); 1172+ efree(scn.sst_tab); 1173 break; 1174 default: 1175 break; 1176@@ -1483,7 +1455,7 @@ 1177 cdf_dump_property_info(const cdf_property_info_t *info, size_t count) 1178 { 1179 cdf_timestamp_t tp; 1180- struct timespec ts; 1181+ struct timeval ts; 1182 char buf[64]; 1183 size_t i, j; 1184 1185@@ -1568,7 +1540,7 @@ 1186 (void)fprintf(stderr, "Class %s\n", buf); 1187 (void)fprintf(stderr, "Count %d\n", ssi.si_count); 1188 cdf_dump_property_info(info, count); 1189- free(info); 1190+ efree(info); 1191 } 1192 1193 1194@@ -1589,7 +1561,7 @@ 1195 cdf_u16tos8(sbuf, ce[i].ce_namlen, ce[i].ce_name), 1196 cdf_ctime(&ts.tv_sec, tbuf)); 1197 } 1198- free(cat); 1199+ efree(cat); 1200 } 1201 1202 #endif 1203diff -u libmagic.orig/cdf.h libmagic/cdf.h 1204--- libmagic.orig/cdf.h 2022-09-24 22:56:49.000000000 +0200 1205+++ libmagic/cdf.h 2024-02-07 10:04:46.577977135 +0100 1206@@ -37,8 +37,6 @@ 1207 1208 #ifdef WIN32 1209 #include <winsock2.h> 1210-#define timespec timeval 1211-#define tv_nsec tv_usec 1212 #endif 1213 #ifdef __DJGPP__ 1214 #define timespec timeval 1215diff -u libmagic.orig/compress.c libmagic/compress.c 1216--- libmagic.orig/compress.c 2023-05-21 17:59:58.000000000 +0200 1217+++ libmagic/compress.c 2024-02-15 19:28:46.036308654 +0100 1218@@ -63,13 +63,14 @@ 1219 #if defined(HAVE_SYS_TIME_H) 1220 #include <sys/time.h> 1221 #endif 1222- 1223-#if defined(HAVE_ZLIB_H) && defined(ZLIBSUPPORT) 1224+#if defined(HAVE_ZLIB_H) && defined(PHP_FILEINFO_UNCOMPRESS) 1225 #define BUILTIN_DECOMPRESS 1226 #include <zlib.h> 1227 #endif 1228 1229-#if defined(HAVE_BZLIB_H) && defined(BZLIBSUPPORT) 1230+#undef FIONREAD 1231+ 1232+#if defined(PHP_FILEINFO_UNCOMPRESS) 1233 #define BUILTIN_BZLIB 1234 #include <bzlib.h> 1235 #endif 1236@@ -132,6 +133,8 @@ 1237 } 1238 #endif 1239 1240+#ifdef PHP_FILEINFO_UNCOMPRESS 1241+ 1242 static int 1243 lzmacmp(const unsigned char *buf) 1244 { 1245@@ -307,7 +310,7 @@ 1246 } 1247 1248 nsz = nbytes; 1249- free(newbuf); 1250+ efree(newbuf); 1251 urv = uncompressbuf(fd, ms->bytes_max, i, 1252 (ms->flags & MAGIC_NO_COMPRESS_FORK), buf, &newbuf, &nsz); 1253 DPRINTF("uncompressbuf = %d, %s, %" SIZE_T_FORMAT "u\n", urv, 1254@@ -319,7 +322,7 @@ 1255 if (urv == ERRDATA) 1256 prv = format_decompression_error(ms, i, newbuf); 1257 else 1258- prv = file_buffer(ms, -1, NULL, name, newbuf, 1259+ prv = file_buffer(ms, NULL, NULL, name, newbuf, 1260 nsz); 1261 if (prv == -1) 1262 goto error; 1263@@ -337,7 +340,7 @@ 1264 * XXX: If file_buffer fails here, we overwrite 1265 * the compressed text. FIXME. 1266 */ 1267- if (file_buffer(ms, -1, NULL, NULL, buf, nbytes) == -1) 1268+ if (file_buffer(ms, NULL, NULL, NULL, buf, nbytes) == -1) 1269 { 1270 if (file_pop_buffer(ms, pb) != NULL) 1271 abort(); 1272@@ -345,10 +348,10 @@ 1273 } 1274 if ((rbuf = file_pop_buffer(ms, pb)) != NULL) { 1275 if (file_printf(ms, "%s", rbuf) == -1) { 1276- free(rbuf); 1277+ efree(rbuf); 1278 goto error; 1279 } 1280- free(rbuf); 1281+ efree(rbuf); 1282 } 1283 if (!mime && file_printf(ms, ")") == -1) 1284 goto error; 1285@@ -369,7 +372,8 @@ 1286 if (sa_saved && sig_act.sa_handler != SIG_IGN) 1287 (void)sigaction(SIGPIPE, &sig_act, NULL); 1288 1289- free(newbuf); 1290+ if (newbuf) 1291+ efree(newbuf); 1292 ms->flags |= MAGIC_COMPRESS; 1293 DPRINTF("Zmagic returns %d\n", rv); 1294 return rv; 1295@@ -452,7 +456,7 @@ 1296 1297 nocheck: 1298 do 1299- switch ((rv = read(fd, buf, n))) { 1300+ switch ((rv = FINFO_READ_FUNC(fd, buf, n))) { 1301 case -1: 1302 if (errno == EINTR) 1303 continue; 1304@@ -545,13 +549,13 @@ 1305 return -1; 1306 } 1307 (void)close(tfd); 1308- if (lseek(fd, CAST(off_t, 0), SEEK_SET) == CAST(off_t, -1)) { 1309+ if (FINFO_LSEEK_FUNC(fd, (zend_off_t)0, SEEK_SET) == (zend_off_t)-1) { 1310 file_badseek(ms); 1311 return -1; 1312 } 1313 return fd; 1314 } 1315-#if HAVE_FORK 1316+#ifdef PHP_FILEINFO_UNCOMPRESS 1317 #ifdef BUILTIN_DECOMPRESS 1318 1319 #define FHCRC (1 << 1) 1320@@ -1062,7 +1066,7 @@ 1321 int (*decompress)(const unsigned char *, unsigned char **, 1322 size_t, size_t *, int) = getdecompressor(method); 1323 1324- *newch = CAST(unsigned char *, malloc(bytes_max + 1)); 1325+ *newch = CAST(unsigned char *, emalloc(bytes_max + 1)); 1326 if (*newch == NULL) 1327 return makeerror(newch, n, "No buffer, %s", strerror(errno)); 1328 1329@@ -1225,3 +1229,4 @@ 1330 return rv; 1331 } 1332 #endif 1333+#endif 1334diff -u libmagic.orig/der.c libmagic/der.c 1335--- libmagic.orig/der.c 2022-09-24 22:56:49.000000000 +0200 1336+++ libmagic/der.c 2024-02-15 19:28:46.036308654 +0100 1337@@ -54,7 +54,9 @@ 1338 #include "magic.h" 1339 #include "der.h" 1340 #else 1341+#ifdef HAVE_SYS_MMAN_H 1342 #include <sys/mman.h> 1343+#endif 1344 #include <sys/stat.h> 1345 #include <err.h> 1346 #endif 1347diff -u libmagic.orig/elfclass.h libmagic/elfclass.h 1348--- libmagic.orig/elfclass.h 2022-09-24 22:56:49.000000000 +0200 1349+++ libmagic/elfclass.h 2023-11-27 19:47:19.275556073 +0100 1350@@ -41,7 +41,7 @@ 1351 return toomany(ms, "program headers", phnum); 1352 flags |= FLAGS_IS_CORE; 1353 if (dophn_core(ms, clazz, swap, fd, 1354- CAST(off_t, elf_getu(swap, elfhdr.e_phoff)), phnum, 1355+ CAST(zend_off_t, elf_getu(swap, elfhdr.e_phoff)), phnum, 1356 CAST(size_t, elf_getu16(swap, elfhdr.e_phentsize)), 1357 fsize, &flags, ¬ecount) == -1) 1358 return -1; 1359@@ -56,7 +56,7 @@ 1360 if (shnum > ms->elf_shnum_max) 1361 return toomany(ms, "section", shnum); 1362 if (dophn_exec(ms, clazz, swap, fd, 1363- CAST(off_t, elf_getu(swap, elfhdr.e_phoff)), phnum, 1364+ CAST(zend_off_t, elf_getu(swap, elfhdr.e_phoff)), phnum, 1365 CAST(size_t, elf_getu16(swap, elfhdr.e_phentsize)), 1366 fsize, shnum, &flags, ¬ecount) == -1) 1367 return -1; 1368@@ -66,7 +66,7 @@ 1369 if (shnum > ms->elf_shnum_max) 1370 return toomany(ms, "section headers", shnum); 1371 if (doshn(ms, clazz, swap, fd, 1372- CAST(off_t, elf_getu(swap, elfhdr.e_shoff)), shnum, 1373+ CAST(zend_off_t, elf_getu(swap, elfhdr.e_shoff)), shnum, 1374 CAST(size_t, elf_getu16(swap, elfhdr.e_shentsize)), 1375 fsize, elf_getu16(swap, elfhdr.e_machine), 1376 CAST(int, elf_getu16(swap, elfhdr.e_shstrndx)), 1377diff -u libmagic.orig/encoding.c libmagic/encoding.c 1378--- libmagic.orig/encoding.c 2022-12-26 18:31:56.000000000 +0100 1379+++ libmagic/encoding.c 2024-02-15 19:28:46.036308654 +0100 1380@@ -97,7 +97,7 @@ 1381 nbytes = ms->encoding_max; 1382 1383 mlen = (nbytes + 1) * sizeof((*ubuf)[0]); 1384- *ubuf = CAST(file_unichar_t *, calloc(CAST(size_t, 1), mlen)); 1385+ *ubuf = CAST(file_unichar_t *, ecalloc(CAST(size_t, 1), mlen)); 1386 if (*ubuf == NULL) { 1387 file_oomem(ms, mlen); 1388 goto done; 1389@@ -150,7 +150,7 @@ 1390 unsigned char *nbuf; 1391 1392 mlen = (nbytes + 1) * sizeof(nbuf[0]); 1393- if ((nbuf = CAST(unsigned char *, malloc(mlen))) == NULL) { 1394+ if ((nbuf = CAST(unsigned char *, emalloc(mlen))) == NULL) { 1395 file_oomem(ms, mlen); 1396 goto done; 1397 } 1398@@ -170,12 +170,12 @@ 1399 rv = 0; 1400 *type = "binary"; 1401 } 1402- free(nbuf); 1403+ efree(nbuf); 1404 } 1405 1406 done: 1407 if (ubuf == &udefbuf) 1408- free(udefbuf); 1409+ efree(udefbuf); 1410 1411 return rv; 1412 } 1413diff -u libmagic.orig/file.h libmagic/file.h 1414--- libmagic.orig/file.h 2023-07-27 21:40:22.000000000 +0200 1415+++ libmagic/file.h 2024-02-15 19:50:18.840553550 +0100 1416@@ -27,15 +27,13 @@ 1417 */ 1418 /* 1419 * file.h - definitions for file(1) program 1420- * @(#)$File: file.h,v 1.247 2023/07/27 19:40:22 christos Exp $ 1421+ * @(#)$File: file.h,v 1.248 2023/07/28 14:38:25 christos Exp $ 1422 */ 1423 1424 #ifndef __file_h__ 1425 #define __file_h__ 1426 1427-#ifdef HAVE_CONFIG_H 1428-#include <config.h> 1429-#endif 1430+#include "config.h" 1431 1432 #ifdef HAVE_STDINT_H 1433 #include <stdint.h> 1434@@ -79,8 +77,7 @@ 1435 #include <stdio.h> /* Include that here, to make sure __P gets defined */ 1436 #include <errno.h> 1437 #include <fcntl.h> /* For open and flags */ 1438-#include <regex.h> 1439-#include <time.h> 1440+ 1441 #include <sys/types.h> 1442 #ifndef WIN32 1443 #include <sys/param.h> 1444@@ -88,10 +85,6 @@ 1445 /* Do this here and now, because struct stat gets re-defined on solaris */ 1446 #include <sys/stat.h> 1447 #include <stdarg.h> 1448-#include <locale.h> 1449-#if defined(HAVE_XLOCALE_H) 1450-#include <xlocale.h> 1451-#endif 1452 1453 #define ENABLE_CONDITIONALS 1454 1455@@ -159,9 +152,11 @@ 1456 /* 1457 * Dec 31, 23:59:59 9999 1458 * we need to make sure that we don't exceed 9999 because some libc 1459- * implementations like muslc crash otherwise 1460+ * implementations like muslc crash otherwise. If you are unlucky 1461+ * to be running on a system with a 32 bit time_t, then it is even less. 1462 */ 1463-#define MAX_CTIME CAST(time_t, 0x3afff487cfULL) 1464+#define MAX_CTIME \ 1465+ CAST(time_t, sizeof(time_t) > 4 ? 0x3afff487cfULL : 0x7fffffffULL) 1466 1467 #define FILE_BADSIZE CAST(size_t, ~0ul) 1468 #define MAXDESC 64 /* max len of text description/MIME type */ 1469@@ -179,14 +174,12 @@ 1470 #define FILE_COMPILE 2 1471 #define FILE_LIST 3 1472 1473-typedef regex_t file_regex_t; 1474- 1475 struct buffer { 1476 int fd; 1477- struct stat st; 1478+ zend_stat_t st; 1479 const void *fbuf; 1480 size_t flen; 1481- off_t eoff; 1482+ zend_off_t eoff; 1483 void *ebuf; 1484 size_t elen; 1485 }; 1486@@ -289,7 +282,7 @@ 1487 #define FILE_OCTAL 59 1488 #define FILE_NAMES_SIZE 60 /* size of array to contain all names */ 1489 1490-#define IS_STRING(t) \ 1491+#define IS_LIBMAGIC_STRING(t) \ 1492 ((t) == FILE_STRING || \ 1493 (t) == FILE_PSTRING || \ 1494 (t) == FILE_BESTRING16 || \ 1495@@ -420,7 +413,6 @@ 1496 /* list of magic entries */ 1497 struct mlist { 1498 struct magic *magic; /* array of magic entries */ 1499- file_regex_t **magic_rxcomp; /* array of compiled regexps */ 1500 size_t nmagic; /* number of entries in array */ 1501 void *map; /* internal resources used by entry */ 1502 struct mlist *next, *prev; 1503@@ -525,11 +517,9 @@ 1504 file_protected const char *file_fmtnum(char *, size_t, const char *, int); 1505 file_protected struct magic_set *file_ms_alloc(int); 1506 file_protected void file_ms_free(struct magic_set *); 1507-file_protected int file_default(struct magic_set *, size_t); 1508-file_protected int file_buffer(struct magic_set *, int, struct stat *, 1509- const char *, const void *, size_t); 1510-file_protected int file_fsmagic(struct magic_set *, const char *, 1511- struct stat *); 1512+file_protected int file_buffer(struct magic_set *, php_stream *, zend_stat_t *, const char *, const void *, 1513+ size_t); 1514+file_protected int file_fsmagic(struct magic_set *, const char *, zend_stat_t *); 1515 file_protected int file_pipe2file(struct magic_set *, int, const void *, 1516 size_t); 1517 file_protected int file_vprintf(struct magic_set *, const char *, va_list) 1518@@ -546,7 +536,7 @@ 1519 file_protected int file_reset(struct magic_set *, int); 1520 file_protected int file_tryelf(struct magic_set *, const struct buffer *); 1521 file_protected int file_trycdf(struct magic_set *, const struct buffer *); 1522-#if HAVE_FORK 1523+#ifdef PHP_FILEINFO_UNCOMPRESS 1524 file_protected int file_zmagic(struct magic_set *, const struct buffer *, 1525 const char *); 1526 #endif 1527@@ -605,19 +595,13 @@ 1528 file_protected int file_clear_closexec(int); 1529 file_protected char *file_strtrim(char *); 1530 1531-file_protected void buffer_init(struct buffer *, int, const struct stat *, 1532+file_protected void buffer_init(struct buffer *, int, const zend_stat_t *, 1533 const void *, size_t); 1534 file_protected void buffer_fini(struct buffer *); 1535 file_protected int buffer_fill(const struct buffer *); 1536 1537 1538 1539-file_protected int file_regcomp(struct magic_set *, file_regex_t *, 1540- const char *, int); 1541-file_protected int file_regexec(struct magic_set *, file_regex_t *, 1542- const char *, size_t, regmatch_t *, int); 1543-file_protected void file_regfree(file_regex_t *); 1544- 1545 typedef struct { 1546 char *buf; 1547 size_t blen; 1548@@ -632,23 +616,10 @@ 1549 extern const size_t file_nnames; 1550 #endif 1551 1552-#ifndef HAVE_PREAD 1553-ssize_t pread(int, void *, size_t, off_t); 1554-#endif 1555-#ifndef HAVE_VASPRINTF 1556-int vasprintf(char **, const char *, va_list); 1557-#endif 1558-#ifndef HAVE_ASPRINTF 1559-int asprintf(char **, const char *, ...); 1560-#endif 1561-#ifndef HAVE_DPRINTF 1562-int dprintf(int, const char *, ...); 1563-#endif 1564- 1565-#ifndef HAVE_STRLCPY 1566+#ifndef strlcpy 1567 size_t strlcpy(char *, const char *, size_t); 1568 #endif 1569-#ifndef HAVE_STRLCAT 1570+#ifndef strlcat 1571 size_t strlcat(char *, const char *, size_t); 1572 #endif 1573 #ifndef HAVE_STRCASESTR 1574@@ -664,39 +635,6 @@ 1575 #ifndef HAVE_ASCTIME_R 1576 char *asctime_r(const struct tm *, char *); 1577 #endif 1578-#ifndef HAVE_GMTIME_R 1579-struct tm *gmtime_r(const time_t *, struct tm *); 1580-#endif 1581-#ifndef HAVE_LOCALTIME_R 1582-struct tm *localtime_r(const time_t *, struct tm *); 1583-#endif 1584-#ifndef HAVE_FMTCHECK 1585-const char *fmtcheck(const char *, const char *) 1586- __attribute__((__format_arg__(2))); 1587-#endif 1588- 1589-#ifdef HAVE_LIBSECCOMP 1590-// basic filter 1591-// this mode should not interfere with normal operations 1592-// only some dangerous syscalls are blacklisted 1593-int enable_sandbox_basic(void); 1594- 1595-// enhanced filter 1596-// this mode allows only the necessary syscalls used during normal operation 1597-// extensive testing required !!! 1598-int enable_sandbox_full(void); 1599-#endif 1600- 1601-file_protected const char *file_getprogname(void); 1602-file_protected void file_setprogname(const char *); 1603-file_protected void file_err(int, const char *, ...) 1604- __attribute__((__format__(__printf__, 2, 3), __noreturn__)); 1605-file_protected void file_errx(int, const char *, ...) 1606- __attribute__((__format__(__printf__, 2, 3), __noreturn__)); 1607-file_protected void file_warn(const char *, ...) 1608- __attribute__((__format__(__printf__, 1, 2))); 1609-file_protected void file_warnx(const char *, ...) 1610- __attribute__((__format__(__printf__, 1, 2))); 1611 1612 #if defined(HAVE_MMAP) && defined(HAVE_SYS_MMAN_H) && !defined(QUICK) 1613 #define QUICK 1614diff -u libmagic.orig/fsmagic.c libmagic/fsmagic.c 1615--- libmagic.orig/fsmagic.c 2023-07-27 21:33:24.000000000 +0200 1616+++ libmagic/fsmagic.c 2024-02-15 19:28:46.036308654 +0100 1617@@ -66,26 +66,10 @@ 1618 # define minor(dev) ((dev) & 0xff) 1619 #endif 1620 #undef HAVE_MAJOR 1621-#ifdef S_IFLNK 1622-file_private int 1623-bad_link(struct magic_set *ms, int err, char *buf) 1624-{ 1625- int mime = ms->flags & MAGIC_MIME; 1626- if ((mime & MAGIC_MIME_TYPE) && 1627- file_printf(ms, "inode/symlink") 1628- == -1) 1629- return -1; 1630- else if (!mime) { 1631- if (ms->flags & MAGIC_ERROR) { 1632- file_error(ms, err, 1633- "broken symbolic link to %s", buf); 1634- return -1; 1635- } 1636- if (file_printf(ms, "broken symbolic link to %s", buf) == -1) 1637- return -1; 1638- } 1639- return 1; 1640-} 1641+ 1642+#ifdef PHP_WIN32 1643+ 1644+# undef S_IFIFO 1645 #endif 1646 file_private int 1647 handle_mime(struct magic_set *ms, int mime, const char *str) 1648@@ -103,60 +87,17 @@ 1649 } 1650 1651 file_protected int 1652-file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb) 1653+file_fsmagic(struct magic_set *ms, const char *fn, zend_stat_t *sb) 1654 { 1655 int ret, did = 0; 1656 int mime = ms->flags & MAGIC_MIME; 1657 int silent = ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION); 1658-#ifdef S_IFLNK 1659- char buf[BUFSIZ+4]; 1660- ssize_t nch; 1661- struct stat tstatbuf; 1662-#endif 1663 1664 if (fn == NULL) 1665 return 0; 1666 1667 #define COMMA (did++ ? ", " : "") 1668- /* 1669- * Fstat is cheaper but fails for files you don't have read perms on. 1670- * On 4.2BSD and similar systems, use lstat() to identify symlinks. 1671- */ 1672-#ifdef S_IFLNK 1673- if ((ms->flags & MAGIC_SYMLINK) == 0) 1674- ret = lstat(fn, sb); 1675- else 1676-#endif 1677- ret = stat(fn, sb); /* don't merge into if; see "ret =" above */ 1678- 1679-#ifdef WIN32 1680- { 1681- HANDLE hFile = CreateFile((LPCSTR)fn, 0, FILE_SHARE_DELETE | 1682- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 1683- NULL); 1684- if (hFile != INVALID_HANDLE_VALUE) { 1685- /* 1686- * Stat failed, but we can still open it - assume it's 1687- * a block device, if nothing else. 1688- */ 1689- if (ret) { 1690- sb->st_mode = S_IFBLK; 1691- ret = 0; 1692- } 1693- switch (GetFileType(hFile)) { 1694- case FILE_TYPE_CHAR: 1695- sb->st_mode |= S_IFCHR; 1696- sb->st_mode &= ~S_IFREG; 1697- break; 1698- case FILE_TYPE_PIPE: 1699- sb->st_mode |= S_IFIFO; 1700- sb->st_mode &= ~S_IFREG; 1701- break; 1702- } 1703- CloseHandle(hFile); 1704- } 1705- } 1706-#endif 1707+ ret = php_sys_stat(fn, sb); 1708 1709 if (ret) { 1710 if (ms->flags & MAGIC_ERROR) { 1711@@ -189,32 +130,24 @@ 1712 } 1713 1714 switch (sb->st_mode & S_IFMT) { 1715- case S_IFDIR: 1716- if (mime) { 1717- if (handle_mime(ms, mime, "directory") == -1) 1718- return -1; 1719- } else if (silent) { 1720- } else if (file_printf(ms, "%sdirectory", COMMA) == -1) 1721- return -1; 1722- break; 1723-#ifdef S_IFCHR 1724- case S_IFCHR: 1725- /* 1726- * If -s has been specified, treat character special files 1727- * like ordinary files. Otherwise, just report that they 1728- * are block special files and go on to the next file. 1729- */ 1730- if ((ms->flags & MAGIC_DEVICES) != 0) { 1731- ret = 0; 1732- break; 1733- } 1734- if (mime) { 1735- if (handle_mime(ms, mime, "chardevice") == -1) 1736- return -1; 1737- } else if (silent) { 1738- } else { 1739-#ifdef HAVE_STRUCT_STAT_ST_RDEV 1740-# ifdef dv_unit 1741+#ifndef PHP_WIN32 1742+# ifdef S_IFCHR 1743+ case S_IFCHR: 1744+ /* 1745+ * If -s has been specified, treat character special files 1746+ * like ordinary files. Otherwise, just report that they 1747+ * are block special files and go on to the next file. 1748+ */ 1749+ if ((ms->flags & MAGIC_DEVICES) != 0) { 1750+ ret = 0; 1751+ break; 1752+ } 1753+ if (mime) { 1754+ if (handle_mime(ms, mime, "chardevice") == -1) 1755+ return -1; 1756+ } else { 1757+# ifdef HAVE_STAT_ST_RDEV 1758+# ifdef dv_unit 1759 if (file_printf(ms, "%scharacter special (%d/%d/%d)", 1760 COMMA, major(sb->st_rdev), dv_unit(sb->st_rdev), 1761 dv_subunit(sb->st_rdev)) == -1) 1762@@ -229,45 +162,11 @@ 1763 if (file_printf(ms, "%scharacter special", COMMA) == -1) 1764 return -1; 1765 #endif 1766- } 1767- break; 1768-#endif 1769-#ifdef S_IFBLK 1770- case S_IFBLK: 1771- /* 1772- * If -s has been specified, treat block special files 1773- * like ordinary files. Otherwise, just report that they 1774- * are block special files and go on to the next file. 1775- */ 1776- if ((ms->flags & MAGIC_DEVICES) != 0) { 1777- ret = 0; 1778- break; 1779- } 1780- if (mime) { 1781- if (handle_mime(ms, mime, "blockdevice") == -1) 1782- return -1; 1783- } else if (silent) { 1784- } else { 1785-#ifdef HAVE_STRUCT_STAT_ST_RDEV 1786-# ifdef dv_unit 1787- if (file_printf(ms, "%sblock special (%d/%d/%d)", 1788- COMMA, major(sb->st_rdev), dv_unit(sb->st_rdev), 1789- dv_subunit(sb->st_rdev)) == -1) 1790- return -1; 1791-# else 1792- if (file_printf(ms, "%sblock special (%ld/%ld)", 1793- COMMA, (long)major(sb->st_rdev), 1794- (long)minor(sb->st_rdev)) == -1) 1795- return -1; 1796+ } 1797+ return 1; 1798 # endif 1799-#else 1800- if (file_printf(ms, "%sblock special", COMMA) == -1) 1801- return -1; 1802 #endif 1803- } 1804- break; 1805-#endif 1806- /* TODO add code to handle V7 MUX and Blit MUX files */ 1807+ 1808 #ifdef S_IFIFO 1809 case S_IFIFO: 1810 if((ms->flags & MAGIC_DEVICES) != 0) 1811@@ -292,92 +191,14 @@ 1812 #endif 1813 #ifdef S_IFLNK 1814 case S_IFLNK: 1815- if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) { 1816+ /* stat is used, if it made here then the link is broken */ 1817 if (ms->flags & MAGIC_ERROR) { 1818- file_error(ms, errno, "unreadable symlink `%s'", 1819- fn); 1820+ file_error(ms, errno, "unreadable symlink `%s'", fn); 1821 return -1; 1822 } 1823- if (mime) { 1824- if (handle_mime(ms, mime, "symlink") == -1) 1825- return -1; 1826- } else if (silent) { 1827- } else if (file_printf(ms, 1828- "%sunreadable symlink `%s' (%s)", COMMA, fn, 1829- strerror(errno)) == -1) 1830- return -1; 1831- break; 1832- } 1833- buf[nch] = '\0'; /* readlink(2) does not do this */ 1834- 1835- /* If broken symlink, say so and quit early. */ 1836-#ifdef __linux__ 1837- /* 1838- * linux procfs/devfs makes symlinks like pipe:[3515864880] 1839- * that we can't stat their readlink output, so stat the 1840- * original filename instead. 1841- */ 1842- if (stat(fn, &tstatbuf) < 0) 1843- return bad_link(ms, errno, buf); 1844-#else 1845- if (*buf == '/') { 1846- if (stat(buf, &tstatbuf) < 0) 1847- return bad_link(ms, errno, buf); 1848- } else { 1849- char *tmp; 1850- char buf2[BUFSIZ+BUFSIZ+4]; 1851- 1852- if ((tmp = CCAST(char *, strrchr(fn, '/'))) == NULL) { 1853- tmp = buf; /* in current directory anyway */ 1854- } else { 1855- if (tmp - fn + 1 > BUFSIZ) { 1856- if (ms->flags & MAGIC_ERROR) { 1857- file_error(ms, 0, 1858- "path too long: `%s'", buf); 1859- return -1; 1860- } 1861- if (mime) { 1862- if (handle_mime(ms, mime, 1863- "x-path-too-long") == -1) 1864- return -1; 1865- } else if (silent) { 1866- } else if (file_printf(ms, 1867- "%spath too long: `%s'", COMMA, 1868- fn) == -1) 1869- return -1; 1870- break; 1871- } 1872- /* take dir part */ 1873- (void)strlcpy(buf2, fn, sizeof buf2); 1874- buf2[tmp - fn + 1] = '\0'; 1875- /* plus (rel) link */ 1876- (void)strlcat(buf2, buf, sizeof buf2); 1877- tmp = buf2; 1878- } 1879- if (stat(tmp, &tstatbuf) < 0) 1880- return bad_link(ms, errno, buf); 1881- } 1882+ return 1; 1883 #endif 1884 1885- /* Otherwise, handle it. */ 1886- if ((ms->flags & MAGIC_SYMLINK) != 0) { 1887- const char *p; 1888- ms->flags &= MAGIC_SYMLINK; 1889- p = magic_file(ms, buf); 1890- ms->flags |= MAGIC_SYMLINK; 1891- if (p == NULL) 1892- return -1; 1893- } else { /* just print what it points to */ 1894- if (mime) { 1895- if (handle_mime(ms, mime, "symlink") == -1) 1896- return -1; 1897- } else if (silent) { 1898- } else if (file_printf(ms, "%ssymbolic link to %s", 1899- COMMA, buf) == -1) 1900- return -1; 1901- } 1902- break; 1903-#endif 1904 #ifdef S_IFSOCK 1905 #ifndef __COHERENT__ 1906 case S_IFSOCK: 1907diff -u libmagic.orig/funcs.c libmagic/funcs.c 1908--- libmagic.orig/funcs.c 2023-07-27 21:40:12.000000000 +0200 1909+++ libmagic/funcs.c 2024-02-15 19:28:46.036308654 +0100 1910@@ -66,7 +66,7 @@ 1911 file_private void 1912 file_clearbuf(struct magic_set *ms) 1913 { 1914- free(ms->o.buf); 1915+ efree(ms->o.buf); 1916 ms->o.buf = NULL; 1917 ms->o.blen = 0; 1918 } 1919@@ -132,7 +132,7 @@ 1920 file_protected int 1921 file_vprintf(struct magic_set *ms, const char *fmt, va_list ap) 1922 { 1923- int len; 1924+ size_t len; 1925 char *buf, *newstr; 1926 char tbuf[1024]; 1927 1928@@ -145,31 +145,25 @@ 1929 return -1; 1930 } 1931 1932- len = vasprintf(&buf, fmt, ap); 1933- if (len < 0 || (size_t)len > 1024 || len + ms->o.blen > 1024 * 1024) { 1934+ len = vspprintf(&buf, 0, fmt, ap); 1935+ if (len > 1024 || len + ms->o.blen > 1024 * 1024) { 1936 size_t blen = ms->o.blen; 1937- free(buf); 1938+ if (buf) efree(buf); 1939 file_clearbuf(ms); 1940- file_error(ms, 0, "Output buffer space exceeded %d+%" 1941+ file_error(ms, 0, "Output buffer space exceeded %" SIZE_T_FORMAT "u+%" 1942 SIZE_T_FORMAT "u", len, blen); 1943 return -1; 1944 } 1945 1946 if (ms->o.buf != NULL) { 1947- len = asprintf(&newstr, "%s%s", ms->o.buf, buf); 1948- free(buf); 1949- if (len < 0) 1950- goto out; 1951- free(ms->o.buf); 1952+ len = spprintf(&newstr, 0, "%s%s", ms->o.buf, buf); 1953+ efree(buf); 1954+ efree(ms->o.buf); 1955 buf = newstr; 1956 } 1957 ms->o.buf = buf; 1958 ms->o.blen = len; 1959 return 0; 1960-out: 1961- file_clearbuf(ms); 1962- file_error(ms, errno, "vasprintf failed"); 1963- return -1; 1964 } 1965 1966 file_protected int 1967@@ -320,7 +314,7 @@ 1968 */ 1969 /*ARGSUSED*/ 1970 file_protected int 1971-file_buffer(struct magic_set *ms, int fd, struct stat *st, 1972+file_buffer(struct magic_set *ms, php_stream *stream, zend_stat_t *st, 1973 const char *inname __attribute__ ((__unused__)), 1974 const void *buf, size_t nb) 1975 { 1976@@ -331,6 +325,19 @@ 1977 const char *ftype = NULL; 1978 char *rbuf = NULL; 1979 struct buffer b; 1980+ int fd = -1; 1981+ 1982+ if (stream) { 1983+#ifdef _WIN64 1984+ php_socket_t _fd = fd; 1985+#else 1986+ int _fd; 1987+#endif 1988+ int _ret = php_stream_cast(stream, PHP_STREAM_AS_FD, (void **)&_fd, 0); 1989+ if (SUCCESS == _ret) { 1990+ fd = (int)_fd; 1991+ } 1992+ } 1993 1994 buffer_init(&b, fd, st, buf, nb); 1995 ms->mode = b.st.st_mode; 1996@@ -363,7 +370,8 @@ 1997 } 1998 } 1999 #endif 2000-#if HAVE_FORK 2001+ 2002+#if PHP_FILEINFO_UNCOMPRESS 2003 /* try compression stuff */ 2004 if ((ms->flags & MAGIC_NO_CHECK_COMPRESS) == 0) { 2005 m = file_zmagic(ms, &b, inname); 2006@@ -447,7 +455,7 @@ 2007 rv = file_tryelf(ms, &b); 2008 rbuf = file_pop_buffer(ms, pb); 2009 if (rv == -1) { 2010- free(rbuf); 2011+ efree(rbuf); 2012 rbuf = NULL; 2013 } 2014 if ((ms->flags & MAGIC_DEBUG) != 0) 2015@@ -499,10 +507,10 @@ 2016 if (file_printf(ms, "%s", code_mime) == -1) 2017 rv = -1; 2018 } 2019-#if HAVE_FORK 2020+#if PHP_FILEINFO_UNCOMPRESS 2021 done_encoding: 2022 #endif 2023- free(rbuf); 2024+ efree(rbuf); 2025 buffer_fini(&b); 2026 if (rv) 2027 return rv; 2028@@ -520,7 +528,7 @@ 2029 } 2030 file_clearbuf(ms); 2031 if (ms->o.pbuf) { 2032- free(ms->o.pbuf); 2033+ efree(ms->o.pbuf); 2034 ms->o.pbuf = NULL; 2035 } 2036 ms->event_flags &= ~EVENT_HAD_ERR; 2037@@ -558,7 +566,7 @@ 2038 return NULL; 2039 } 2040 psize = len * 4 + 1; 2041- if ((pbuf = CAST(char *, realloc(ms->o.pbuf, psize))) == NULL) { 2042+ if ((pbuf = CAST(char *, erealloc(ms->o.pbuf, psize))) == NULL) { 2043 file_oomem(ms, psize); 2044 return NULL; 2045 } 2046@@ -622,8 +630,8 @@ 2047 if (level >= ms->c.len) { 2048 len = (ms->c.len = 20 + level) * sizeof(*ms->c.li); 2049 ms->c.li = CAST(struct level_info *, (ms->c.li == NULL) ? 2050- malloc(len) : 2051- realloc(ms->c.li, len)); 2052+ emalloc(len) : 2053+ erealloc(ms->c.li, len)); 2054 if (ms->c.li == NULL) { 2055 file_oomem(ms, len); 2056 return -1; 2057@@ -646,122 +654,38 @@ 2058 file_protected int 2059 file_replace(struct magic_set *ms, const char *pat, const char *rep) 2060 { 2061- file_regex_t rx; 2062- int rc, rv = -1; 2063- 2064- rc = file_regcomp(ms, &rx, pat, REG_EXTENDED); 2065- if (rc == 0) { 2066- regmatch_t rm; 2067- int nm = 0; 2068- while (file_regexec(ms, &rx, ms->o.buf, 1, &rm, 0) == 0) { 2069- ms->o.buf[rm.rm_so] = '\0'; 2070- if (file_printf(ms, "%s%s", rep, 2071- rm.rm_eo != 0 ? ms->o.buf + rm.rm_eo : "") == -1) 2072- goto out; 2073- nm++; 2074- } 2075- rv = nm; 2076+ zend_string *pattern; 2077+ uint32_t opts = 0; 2078+ pcre_cache_entry *pce; 2079+ zend_string *res; 2080+ zend_string *repl; 2081+ size_t rep_cnt = 0; 2082+ 2083+ opts |= PCRE2_MULTILINE; 2084+ pattern = convert_libmagic_pattern((char*)pat, strlen(pat), opts); 2085+ if ((pce = pcre_get_compiled_regex_cache_ex(pattern, 0)) == NULL) { 2086+ zend_string_release(pattern); 2087+ rep_cnt = -1; 2088+ goto out; 2089+ } 2090+ zend_string_release(pattern); 2091+ 2092+ repl = zend_string_init(rep, strlen(rep), 0); 2093+ res = php_pcre_replace_impl(pce, NULL, ms->o.buf, strlen(ms->o.buf), repl, -1, &rep_cnt); 2094+ 2095+ zend_string_release_ex(repl, 0); 2096+ if (NULL == res) { 2097+ rep_cnt = -1; 2098+ goto out; 2099 } 2100-out: 2101- file_regfree(&rx); 2102- return rv; 2103-} 2104 2105-file_private int 2106-check_regex(struct magic_set *ms, const char *pat) 2107-{ 2108- char sbuf[512]; 2109- unsigned char oc = '\0'; 2110- const char *p; 2111+ memcpy(ms->o.buf, ZSTR_VAL(res), ZSTR_LEN(res)); 2112+ ms->o.buf[ZSTR_LEN(res)] = '\0'; 2113 2114- for (p = pat; *p; p++) { 2115- unsigned char c = *p; 2116- // Avoid repetition 2117- if (c == oc && strchr("?*+{", c) != NULL) { 2118- size_t len = strlen(pat); 2119- file_magwarn(ms, 2120- "repetition-operator operand `%c' " 2121- "invalid in regex `%s'", c, 2122- file_printable(ms, sbuf, sizeof(sbuf), pat, len)); 2123- return -1; 2124- } 2125- oc = c; 2126- if (isprint(c) || isspace(c) || c == '\b' 2127- || c == 0x8a) // XXX: apple magic fixme 2128- continue; 2129- size_t len = strlen(pat); 2130- file_magwarn(ms, 2131- "non-ascii characters in regex \\%#o `%s'", 2132- c, file_printable(ms, sbuf, sizeof(sbuf), pat, len)); 2133- return -1; 2134- } 2135- return 0; 2136-} 2137+ zend_string_release_ex(res, 0); 2138 2139-file_protected int 2140-file_regcomp(struct magic_set *ms file_locale_used, file_regex_t *rx, 2141- const char *pat, int flags) 2142-{ 2143- if (check_regex(ms, pat) == -1) 2144- return -1; 2145- 2146-#ifdef USE_C_LOCALE 2147- locale_t old = uselocale(ms->c_lc_ctype); 2148- assert(old != NULL); 2149-#else 2150- char old[1024]; 2151- strlcpy(old, setlocale(LC_CTYPE, NULL), sizeof(old)); 2152- (void)setlocale(LC_CTYPE, "C"); 2153-#endif 2154- int rc; 2155- rc = regcomp(rx, pat, flags); 2156- 2157-#ifdef USE_C_LOCALE 2158- uselocale(old); 2159-#else 2160- (void)setlocale(LC_CTYPE, old); 2161-#endif 2162- if (rc > 0 && (ms->flags & MAGIC_CHECK)) { 2163- char errmsg[512], buf[512]; 2164- 2165- (void)regerror(rc, rx, errmsg, sizeof(errmsg)); 2166- file_magerror(ms, "regex error %d for `%s', (%s)", rc, 2167- file_printable(ms, buf, sizeof(buf), pat, strlen(pat)), 2168- errmsg); 2169- } 2170- return rc; 2171-} 2172- 2173-/*ARGSUSED*/ 2174-file_protected int 2175-file_regexec(struct magic_set *ms file_locale_used, file_regex_t *rx, 2176- const char *str, size_t nmatch, regmatch_t* pmatch, int eflags) 2177-{ 2178-#ifdef USE_C_LOCALE 2179- locale_t old = uselocale(ms->c_lc_ctype); 2180- assert(old != NULL); 2181-#else 2182- char old[1024]; 2183- strlcpy(old, setlocale(LC_CTYPE, NULL), sizeof(old)); 2184- (void)setlocale(LC_CTYPE, "C"); 2185-#endif 2186- int rc; 2187- /* XXX: force initialization because glibc does not always do this */ 2188- if (nmatch != 0) 2189- memset(pmatch, 0, nmatch * sizeof(*pmatch)); 2190- rc = regexec(rx, str, nmatch, pmatch, eflags); 2191-#ifdef USE_C_LOCALE 2192- uselocale(old); 2193-#else 2194- (void)setlocale(LC_CTYPE, old); 2195-#endif 2196- return rc; 2197-} 2198- 2199-file_protected void 2200-file_regfree(file_regex_t *rx) 2201-{ 2202- regfree(rx); 2203+out: 2204+ return rep_cnt; 2205 } 2206 2207 file_protected file_pushbuf_t * 2208@@ -772,7 +696,7 @@ 2209 if (ms->event_flags & EVENT_HAD_ERR) 2210 return NULL; 2211 2212- if ((pb = (CAST(file_pushbuf_t *, malloc(sizeof(*pb))))) == NULL) 2213+ if ((pb = (CAST(file_pushbuf_t *, emalloc(sizeof(*pb))))) == NULL) 2214 return NULL; 2215 2216 pb->buf = ms->o.buf; 2217@@ -792,8 +716,8 @@ 2218 char *rbuf; 2219 2220 if (ms->event_flags & EVENT_HAD_ERR) { 2221- free(pb->buf); 2222- free(pb); 2223+ efree(pb->buf); 2224+ efree(pb); 2225 return NULL; 2226 } 2227 2228@@ -803,7 +727,7 @@ 2229 ms->o.blen = pb->blen; 2230 ms->offset = pb->offset; 2231 2232- free(pb); 2233+ efree(pb); 2234 return rbuf; 2235 } 2236 2237@@ -887,6 +811,7 @@ 2238 #endif 2239 } 2240 2241+#if 0 2242 file_protected int 2243 file_pipe_closexec(int *fds) 2244 { 2245@@ -904,6 +829,7 @@ 2246 return 0; 2247 #endif 2248 } 2249+#endif 2250 2251 file_protected int 2252 file_clear_closexec(int fd) { 2253diff -u libmagic.orig/magic.c libmagic/magic.c 2254--- libmagic.orig/magic.c 2023-07-27 21:33:24.000000000 +0200 2255+++ libmagic/magic.c 2024-02-15 19:28:46.036308654 +0100 2256@@ -25,11 +25,6 @@ 2257 * SUCH DAMAGE. 2258 */ 2259 2260-#ifdef WIN32 2261-#include <windows.h> 2262-#include <shlwapi.h> 2263-#endif 2264- 2265 #include "file.h" 2266 2267 #ifndef lint 2268@@ -39,7 +34,9 @@ 2269 #include "magic.h" 2270 2271 #include <stdlib.h> 2272+#ifdef HAVE_UNISTD_H 2273 #include <unistd.h> 2274+#endif 2275 #include <string.h> 2276 #ifdef QUICK 2277 #include <sys/mman.h> 2278@@ -69,200 +66,18 @@ 2279 #endif 2280 #endif 2281 2282-file_private void close_and_restore(const struct magic_set *, const char *, int, 2283- const struct stat *); 2284-file_private int unreadable_info(struct magic_set *, mode_t, const char *); 2285-file_private const char* get_default_magic(void); 2286-#ifndef COMPILE_ONLY 2287-file_private const char *file_or_fd(struct magic_set *, const char *, int); 2288+#ifdef PHP_WIN32 2289+# undef S_IFLNK 2290+# undef S_IFIFO 2291 #endif 2292 2293+file_private int unreadable_info(struct magic_set *, mode_t, const char *); 2294+file_private const char *file_or_stream(struct magic_set *, const char *, php_stream *); 2295+ 2296 #ifndef STDIN_FILENO 2297 #define STDIN_FILENO 0 2298 #endif 2299 2300-#ifdef WIN32 2301-/* HINSTANCE of this shared library. Needed for get_default_magic() */ 2302-static HINSTANCE _w32_dll_instance = NULL; 2303- 2304-static void 2305-_w32_append_path(char **hmagicpath, const char *fmt, ...) 2306-{ 2307- char *tmppath; 2308- char *newpath; 2309- va_list ap; 2310- 2311- va_start(ap, fmt); 2312- if (vasprintf(&tmppath, fmt, ap) < 0) { 2313- va_end(ap); 2314- return; 2315- } 2316- va_end(ap); 2317- 2318- if (access(tmppath, R_OK) == -1) 2319- goto out; 2320- 2321- if (*hmagicpath == NULL) { 2322- *hmagicpath = tmppath; 2323- return; 2324- } 2325- 2326- if (asprintf(&newpath, "%s%c%s", *hmagicpath, PATHSEP, tmppath) < 0) 2327- goto out; 2328- 2329- free(*hmagicpath); 2330- free(tmppath); 2331- *hmagicpath = newpath; 2332- return; 2333-out: 2334- free(tmppath); 2335-} 2336- 2337-static void 2338-_w32_get_magic_relative_to(char **hmagicpath, HINSTANCE module) 2339-{ 2340- static const char *trypaths[] = { 2341- "%s/share/misc/magic.mgc", 2342- "%s/magic.mgc", 2343- }; 2344- LPSTR dllpath; 2345- size_t sp; 2346- 2347- dllpath = calloc(MAX_PATH + 1, sizeof(*dllpath)); 2348- 2349- if (!GetModuleFileNameA(module, dllpath, MAX_PATH)) 2350- goto out; 2351- 2352- PathRemoveFileSpecA(dllpath); 2353- 2354- if (module) { 2355- char exepath[MAX_PATH]; 2356- GetModuleFileNameA(NULL, exepath, MAX_PATH); 2357- PathRemoveFileSpecA(exepath); 2358- if (stricmp(exepath, dllpath) == 0) 2359- goto out; 2360- } 2361- 2362- sp = strlen(dllpath); 2363- if (sp > 3 && stricmp(&dllpath[sp - 3], "bin") == 0) { 2364- _w32_append_path(hmagicpath, 2365- "%s/../share/misc/magic.mgc", dllpath); 2366- goto out; 2367- } 2368- 2369- for (sp = 0; sp < __arraycount(trypaths); sp++) 2370- _w32_append_path(hmagicpath, trypaths[sp], dllpath); 2371-out: 2372- free(dllpath); 2373-} 2374- 2375-#ifndef BUILD_AS_WINDOWS_STATIC_LIBARAY 2376-/* Placate GCC by offering a sacrificial previous prototype */ 2377-BOOL WINAPI DllMain(HINSTANCE, DWORD, LPVOID); 2378- 2379-BOOL WINAPI 2380-DllMain(HINSTANCE hinstDLL, DWORD fdwReason, 2381- LPVOID lpvReserved __attribute__((__unused__))) 2382-{ 2383- if (fdwReason == DLL_PROCESS_ATTACH) 2384- _w32_dll_instance = hinstDLL; 2385- return 1; 2386-} 2387-#endif 2388-#endif 2389- 2390-file_private const char * 2391-get_default_magic(void) 2392-{ 2393- static const char hmagic[] = "/.magic/magic.mgc"; 2394- static char *default_magic; 2395- char *home, *hmagicpath; 2396- 2397-#ifndef WIN32 2398- struct stat st; 2399- 2400- if (default_magic) { 2401- free(default_magic); 2402- default_magic = NULL; 2403- } 2404- if ((home = getenv("HOME")) == NULL) 2405- return MAGIC; 2406- 2407- if (asprintf(&hmagicpath, "%s/.magic.mgc", home) < 0) 2408- return MAGIC; 2409- if (stat(hmagicpath, &st) == -1) { 2410- free(hmagicpath); 2411- if (asprintf(&hmagicpath, "%s/.magic", home) < 0) 2412- return MAGIC; 2413- if (stat(hmagicpath, &st) == -1) 2414- goto out; 2415- if (S_ISDIR(st.st_mode)) { 2416- free(hmagicpath); 2417- if (asprintf(&hmagicpath, "%s/%s", home, hmagic) < 0) 2418- return MAGIC; 2419- if (access(hmagicpath, R_OK) == -1) 2420- goto out; 2421- } 2422- } 2423- 2424- if (asprintf(&default_magic, "%s:%s", hmagicpath, MAGIC) < 0) 2425- goto out; 2426- free(hmagicpath); 2427- return default_magic; 2428-out: 2429- default_magic = NULL; 2430- free(hmagicpath); 2431- return MAGIC; 2432-#else 2433- hmagicpath = NULL; 2434- 2435- if (default_magic) { 2436- free(default_magic); 2437- default_magic = NULL; 2438- } 2439- 2440- /* Before anything else, try to get a magic file from user HOME */ 2441- if ((home = getenv("HOME")) != NULL) 2442- _w32_append_path(&hmagicpath, "%s%s", home, hmagic); 2443- 2444- /* First, try to get a magic file from user-application data */ 2445- if ((home = getenv("LOCALAPPDATA")) != NULL) 2446- _w32_append_path(&hmagicpath, "%s%s", home, hmagic); 2447- 2448- /* Second, try to get a magic file from the user profile data */ 2449- if ((home = getenv("USERPROFILE")) != NULL) 2450- _w32_append_path(&hmagicpath, 2451- "%s/Local Settings/Application Data%s", home, hmagic); 2452- 2453- /* Third, try to get a magic file from Common Files */ 2454- if ((home = getenv("COMMONPROGRAMFILES")) != NULL) 2455- _w32_append_path(&hmagicpath, "%s%s", home, hmagic); 2456- 2457- /* Fourth, try to get magic file relative to exe location */ 2458- _w32_get_magic_relative_to(&hmagicpath, NULL); 2459- 2460- /* Fifth, try to get magic file relative to dll location */ 2461- _w32_get_magic_relative_to(&hmagicpath, _w32_dll_instance); 2462- 2463- /* Avoid MAGIC constant - it likely points to a file within MSys tree */ 2464- default_magic = hmagicpath; 2465- return default_magic; 2466-#endif 2467-} 2468- 2469-file_public const char * 2470-magic_getpath(const char *magicfile, int action) 2471-{ 2472- if (magicfile != NULL) 2473- return magicfile; 2474- 2475- magicfile = getenv("MAGIC"); 2476- if (magicfile != NULL) 2477- return magicfile; 2478- 2479- return action == FILE_LOAD ? get_default_magic() : MAGIC; 2480-} 2481- 2482 file_public struct magic_set * 2483 magic_open(int flags) 2484 { 2485@@ -321,21 +136,6 @@ 2486 return file_apprentice(ms, magicfile, FILE_LOAD); 2487 } 2488 2489-#ifndef COMPILE_ONLY 2490-/* 2491- * Install a set of compiled magic buffers. 2492- */ 2493-file_public int 2494-magic_load_buffers(struct magic_set *ms, void **bufs, size_t *sizes, 2495- size_t nbufs) 2496-{ 2497- if (ms == NULL) 2498- return -1; 2499- return buffer_apprentice(ms, RCAST(struct magic **, bufs), 2500- sizes, nbufs); 2501-} 2502-#endif 2503- 2504 file_public int 2505 magic_compile(struct magic_set *ms, const char *magicfile) 2506 { 2507@@ -360,39 +160,6 @@ 2508 return file_apprentice(ms, magicfile, FILE_LIST); 2509 } 2510 2511-file_private void 2512-close_and_restore(const struct magic_set *ms, const char *name, int fd, 2513- const struct stat *sb) 2514-{ 2515- if (fd == STDIN_FILENO || name == NULL) 2516- return; 2517- (void) close(fd); 2518- 2519- if ((ms->flags & MAGIC_PRESERVE_ATIME) != 0) { 2520- /* 2521- * Try to restore access, modification times if read it. 2522- * This is really *bad* because it will modify the status 2523- * time of the file... And of course this will affect 2524- * backup programs 2525- */ 2526-#ifdef HAVE_UTIMES 2527- struct timeval utsbuf[2]; 2528- (void)memset(utsbuf, 0, sizeof(utsbuf)); 2529- utsbuf[0].tv_sec = sb->st_atime; 2530- utsbuf[1].tv_sec = sb->st_mtime; 2531- 2532- (void) utimes(name, utsbuf); /* don't care if loses */ 2533-#elif defined(HAVE_UTIME_H) || defined(HAVE_SYS_UTIME_H) 2534- struct utimbuf utbuf; 2535- 2536- (void)memset(&utbuf, 0, sizeof(utbuf)); 2537- utbuf.actime = sb->st_atime; 2538- utbuf.modtime = sb->st_mtime; 2539- (void) utime(name, &utbuf); /* don't care if loses */ 2540-#endif 2541- } 2542-} 2543- 2544 #ifndef COMPILE_ONLY 2545 2546 /* 2547@@ -403,7 +170,7 @@ 2548 { 2549 if (ms == NULL) 2550 return NULL; 2551- return file_or_fd(ms, NULL, fd); 2552+ return file_or_stream(ms, NULL, NULL); 2553 } 2554 2555 /* 2556@@ -414,19 +181,25 @@ 2557 { 2558 if (ms == NULL) 2559 return NULL; 2560- return file_or_fd(ms, inname, STDIN_FILENO); 2561+ return file_or_stream(ms, inname, NULL); 2562+} 2563+ 2564+file_public const char * 2565+magic_stream(struct magic_set *ms, php_stream *stream) 2566+{ 2567+ if (ms == NULL) 2568+ return NULL; 2569+ return file_or_stream(ms, NULL, stream); 2570 } 2571 2572 file_private const char * 2573-file_or_fd(struct magic_set *ms, const char *inname, int fd) 2574+file_or_stream(struct magic_set *ms, const char *inname, php_stream *stream) 2575 { 2576 int rv = -1; 2577 unsigned char *buf; 2578- struct stat sb; 2579+ zend_stat_t sb = {0}; 2580 ssize_t nbytes = 0; /* number of bytes read from a datafile */ 2581- int ispipe = 0; 2582- int okstat = 0; 2583- off_t pos = CAST(off_t, -1); 2584+ int no_in_stream = 0; 2585 2586 if (file_reset(ms, 1) == -1) 2587 goto out; 2588@@ -436,7 +209,7 @@ 2589 * some overlapping space for matches near EOF 2590 */ 2591 #define SLOP (1 + sizeof(union VALUETYPE)) 2592- if ((buf = CAST(unsigned char *, malloc(ms->bytes_max + SLOP))) == NULL) 2593+ if ((buf = CAST(unsigned char *, emalloc(ms->bytes_max + SLOP))) == NULL) 2594 return NULL; 2595 2596 switch (file_fsmagic(ms, inname, &sb)) { 2597@@ -449,96 +222,46 @@ 2598 goto done; 2599 } 2600 2601-#ifdef WIN32 2602- /* Place stdin in binary mode, so EOF (Ctrl+Z) doesn't stop early. */ 2603- if (fd == STDIN_FILENO) 2604- _setmode(STDIN_FILENO, O_BINARY); 2605-#endif 2606- if (inname != NULL) { 2607- int flags = O_RDONLY|O_BINARY|O_NONBLOCK|O_CLOEXEC; 2608- errno = 0; 2609- if ((fd = open(inname, flags)) < 0) { 2610- okstat = stat(inname, &sb) == 0; 2611-#ifdef WIN32 2612- /* 2613- * Can't stat, can't open. It may have been opened in 2614- * fsmagic, so if the user doesn't have read permission, 2615- * allow it to say so; otherwise an error was probably 2616- * displayed in fsmagic. 2617- */ 2618- if (!okstat && errno == EACCES) { 2619- sb.st_mode = S_IFBLK; 2620- okstat = 1; 2621- } 2622-#endif 2623- if (okstat && 2624- unreadable_info(ms, sb.st_mode, inname) == -1) 2625+ errno = 0; 2626+ 2627+ if (inname && !stream) { 2628+ no_in_stream = 1; 2629+ stream = php_stream_open_wrapper((char *)inname, "rb", REPORT_ERRORS, NULL); 2630+ if (!stream) { 2631+ if (unreadable_info(ms, sb.st_mode, inname) == -1) 2632 goto done; 2633- rv = 0; 2634+ rv = -1; 2635 goto done; 2636 } 2637-#if O_CLOEXEC == 0 && defined(F_SETFD) 2638- (void)fcntl(fd, F_SETFD, FD_CLOEXEC); 2639-#endif 2640 } 2641 2642- if (fd != -1) { 2643- okstat = fstat(fd, &sb) == 0; 2644- if (okstat && S_ISFIFO(sb.st_mode)) 2645- ispipe = 1; 2646- if (inname == NULL) 2647- pos = lseek(fd, CAST(off_t, 0), SEEK_CUR); 2648+ php_stream_statbuf ssb; 2649+ if (php_stream_stat(stream, &ssb) < 0) { 2650+ if (ms->flags & MAGIC_ERROR) { 2651+ file_error(ms, errno, "cannot stat `%s'", inname); 2652+ rv = -1; 2653+ goto done; 2654+ } 2655 } 2656+ memcpy(&sb, &ssb.sb, sizeof(zend_stat_t)); 2657 2658 /* 2659 * try looking at the first ms->bytes_max bytes 2660 */ 2661- if (ispipe) { 2662- if (fd != -1) { 2663- ssize_t r = 0; 2664- 2665- while ((r = sread(fd, RCAST(void *, &buf[nbytes]), 2666- CAST(size_t, ms->bytes_max - nbytes), 1)) > 0) { 2667- nbytes += r; 2668- if (r < PIPE_BUF) break; 2669- } 2670- } 2671- 2672- if (nbytes == 0 && inname) { 2673- /* We can not read it, but we were able to stat it. */ 2674- if (unreadable_info(ms, sb.st_mode, inname) == -1) 2675- goto done; 2676- rv = 0; 2677- goto done; 2678- } 2679- 2680- } else if (fd != -1) { 2681- /* Windows refuses to read from a big console buffer. */ 2682- size_t howmany = 2683-#ifdef WIN32 2684- _isatty(fd) ? 8 * 1024 : 2685-#endif 2686- ms->bytes_max; 2687- if ((nbytes = read(fd, RCAST(void *, buf), howmany)) == -1) { 2688- if (inname == NULL && fd != STDIN_FILENO) 2689- file_error(ms, errno, "cannot read fd %d", fd); 2690- else 2691- file_error(ms, errno, "cannot read `%s'", 2692- inname == NULL ? "/dev/stdin" : inname); 2693- goto done; 2694- } 2695+ if ((nbytes = php_stream_read(stream, (char *)buf, ms->bytes_max - nbytes)) < 0) { 2696+ file_error(ms, errno, "cannot read `%s'", inname); 2697+ goto done; 2698 } 2699 2700 (void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */ 2701- if (file_buffer(ms, fd, okstat ? &sb : NULL, inname, buf, CAST(size_t, nbytes)) == -1) 2702+ if (file_buffer(ms, stream, &sb, inname, buf, CAST(size_t, nbytes)) == -1) 2703 goto done; 2704 rv = 0; 2705 done: 2706- free(buf); 2707- if (fd != -1) { 2708- if (pos != CAST(off_t, -1)) 2709- (void)lseek(fd, pos, SEEK_SET); 2710- close_and_restore(ms, inname, fd, &sb); 2711+ efree(buf); 2712+ 2713+ if (no_in_stream && stream) { 2714+ php_stream_close(stream); 2715 } 2716 out: 2717 return rv == 0 ? file_getbuffer(ms) : NULL; 2718@@ -556,7 +279,7 @@ 2719 * The main work is done here! 2720 * We have the file name and/or the data buffer to be identified. 2721 */ 2722- if (file_buffer(ms, -1, NULL, NULL, buf, nb) == -1) { 2723+ if (file_buffer(ms, NULL, NULL, NULL, buf, nb) == -1) { 2724 return NULL; 2725 } 2726 return file_getbuffer(ms); 2727diff -u libmagic.orig/magic.h libmagic/magic.h 2728--- libmagic.orig/magic.h 2024-02-15 19:52:41.323552388 +0100 2729+++ libmagic/magic.h 2024-02-15 19:28:46.036308654 +0100 2730@@ -47,8 +47,6 @@ 2731 * extensions */ 2732 #define MAGIC_COMPRESS_TRANSP 0x2000000 /* Check inside compressed files 2733 * but not report compression */ 2734-#define MAGIC_NO_COMPRESS_FORK 0x4000000 /* Don't allow decompression that 2735- * needs to fork */ 2736 #define MAGIC_NODESC (MAGIC_EXTENSION|MAGIC_MIME|MAGIC_APPLE) 2737 2738 #define MAGIC_NO_CHECK_COMPRESS 0x0001000 /* Don't check for compressed files */ 2739@@ -77,7 +75,7 @@ 2740 MAGIC_NO_CHECK_TOKENS | \ 2741 MAGIC_NO_CHECK_ENCODING | \ 2742 MAGIC_NO_CHECK_JSON | \ 2743- MAGIC_NO_CHECK_SIMH | \ 2744+ MAGIC_NO_CHECK_SIMH | \ 2745 0 \ 2746 ) 2747 2748@@ -101,11 +99,11 @@ 2749 b\20no_check_elf\0\ 2750 b\21no_check_text\0\ 2751 b\22no_check_cdf\0\ 2752-b\23no_check_csv\0\ 2753+b\23no_check_reserved0\0\ 2754 b\24no_check_tokens\0\ 2755 b\25no_check_encoding\0\ 2756 b\26no_check_json\0\ 2757-b\27no_check_simh\0\ 2758+b\27no_check_reserved2\0\ 2759 b\30extension\0\ 2760 b\31transp_compression\0\ 2761 " 2762@@ -130,6 +128,7 @@ 2763 2764 const char *magic_getpath(const char *, int); 2765 const char *magic_file(magic_t, const char *); 2766+const char *magic_stream(magic_t, php_stream *); 2767 const char *magic_descriptor(magic_t, int); 2768 const char *magic_buffer(magic_t, const void *, size_t); 2769 2770@@ -154,7 +153,8 @@ 2771 #define MAGIC_PARAM_REGEX_MAX 5 2772 #define MAGIC_PARAM_BYTES_MAX 6 2773 #define MAGIC_PARAM_ENCODING_MAX 7 2774-#define MAGIC_PARAM_ELF_SHSIZE_MAX 8 2775+#define MAGIC_PARAM_ELF_SHSIZE_MAX 8 2776+#define MAGIC_PARAM_MAGWARN_MAX 9 2777 2778 int magic_setparam(magic_t, int, const void *); 2779 int magic_getparam(magic_t, int, void *); 2780diff -u libmagic.orig/print.c libmagic/print.c 2781--- libmagic.orig/print.c 2023-07-27 20:04:45.000000000 +0200 2782+++ libmagic/print.c 2024-02-15 19:28:46.036308654 +0100 2783@@ -73,7 +73,7 @@ 2784 if (m->mask_op & FILE_OPINVERSE) 2785 (void) fputc('~', stderr); 2786 2787- if (IS_STRING(m->type)) { 2788+ if (IS_LIBMAGIC_STRING(m->type)) { 2789 if (m->str_flags) { 2790 (void) fputc('/', stderr); 2791 if (m->str_flags & STRING_COMPACT_WHITESPACE) 2792@@ -246,18 +246,18 @@ 2793 file_magwarn(struct magic_set *ms, const char *f, ...) 2794 { 2795 va_list va; 2796+ char *expanded_format = NULL; 2797+ int expanded_len; 2798 2799- /* cuz we use stdout for most, stderr here */ 2800- (void) fflush(stdout); 2801- 2802- if (ms && ms->file) 2803- (void) fprintf(stderr, "%s, %lu: ", ms->file, 2804- CAST(unsigned long, ms->line)); 2805- (void) fprintf(stderr, "Warning: "); 2806 va_start(va, f); 2807- (void) vfprintf(stderr, f, va); 2808+ expanded_len = vasprintf(&expanded_format, f, va); 2809 va_end(va); 2810- (void) fputc('\n', stderr); 2811+ 2812+ if (expanded_len >= 0 && expanded_format) { 2813+ php_error_docref(NULL, E_WARNING, "%s", expanded_format); 2814+ 2815+ free(expanded_format); 2816+ } 2817 } 2818 2819 file_protected const char * 2820@@ -289,13 +289,13 @@ 2821 goto out; 2822 2823 if (flags & FILE_T_LOCAL) { 2824- tm = localtime_r(&t, &tmz); 2825+ tm = php_localtime_r(&t, &tmz); 2826 } else { 2827- tm = gmtime_r(&t, &tmz); 2828+ tm = php_gmtime_r(&t, &tmz); 2829 } 2830 if (tm == NULL) 2831 goto out; 2832- pp = asctime_r(tm, buf); 2833+ pp = php_asctime_r(tm, buf); 2834 2835 if (pp == NULL) 2836 goto out; 2837diff -u libmagic.orig/readcdf.c libmagic/readcdf.c 2838--- libmagic.orig/readcdf.c 2023-02-09 18:43:53.000000000 +0100 2839+++ libmagic/readcdf.c 2024-02-15 19:28:46.036308654 +0100 2840@@ -31,7 +31,9 @@ 2841 2842 #include <assert.h> 2843 #include <stdlib.h> 2844+#ifdef HAVE_UNISTD_H 2845 #include <unistd.h> 2846+#endif 2847 #include <string.h> 2848 #include <time.h> 2849 #include <ctype.h> 2850@@ -100,10 +102,6 @@ 2851 if (clsid[0] == cv[i].clsid[0] && clsid[1] == cv[i].clsid[1]) 2852 return cv[i].mime; 2853 } 2854-#ifdef CDF_DEBUG 2855- fprintf(stderr, "unknown mime %" PRIx64 ", %" PRIx64 "\n", clsid[0], 2856- clsid[1]); 2857-#endif 2858 return NULL; 2859 } 2860 2861@@ -112,35 +110,24 @@ 2862 { 2863 size_t i; 2864 const char *rv = NULL; 2865-#ifdef USE_C_LOCALE 2866- locale_t old_lc_ctype, c_lc_ctype; 2867+ char *vbuf_lower; 2868 2869- c_lc_ctype = newlocale(LC_CTYPE_MASK, "C", 0); 2870- assert(c_lc_ctype != NULL); 2871- old_lc_ctype = uselocale(c_lc_ctype); 2872- assert(old_lc_ctype != NULL); 2873-#else 2874- char *old_lc_ctype = setlocale(LC_CTYPE, NULL); 2875- assert(old_lc_ctype != NULL); 2876- old_lc_ctype = strdup(old_lc_ctype); 2877- assert(old_lc_ctype != NULL); 2878- (void)setlocale(LC_CTYPE, "C"); 2879-#endif 2880- for (i = 0; nv[i].pattern != NULL; i++) 2881- if (strcasestr(vbuf, nv[i].pattern) != NULL) { 2882+ vbuf_lower = zend_str_tolower_dup(vbuf, strlen(vbuf)); 2883+ for (i = 0; nv[i].pattern != NULL; i++) { 2884+ char *pattern_lower; 2885+ int found; 2886+ 2887+ pattern_lower = zend_str_tolower_dup(nv[i].pattern, strlen(nv[i].pattern)); 2888+ found = (strstr(vbuf_lower, pattern_lower) != NULL); 2889+ efree(pattern_lower); 2890+ 2891+ if (found) { 2892 rv = nv[i].mime; 2893 break; 2894 } 2895-#ifdef CDF_DEBUG 2896- fprintf(stderr, "unknown app %s\n", vbuf); 2897-#endif 2898-#ifdef USE_C_LOCALE 2899- (void)uselocale(old_lc_ctype); 2900- freelocale(c_lc_ctype); 2901-#else 2902- (void)setlocale(LC_CTYPE, old_lc_ctype); 2903- free(old_lc_ctype); 2904-#endif 2905+ } 2906+ 2907+ efree(vbuf_lower); 2908 return rv; 2909 } 2910 2911@@ -156,6 +143,8 @@ 2912 const char *s, *e; 2913 int len; 2914 2915+ memset(&ts, 0, sizeof(ts)); 2916+ 2917 if (!NOTMIME(ms) && root_storage) 2918 str = cdf_clsid_to_mime(root_storage->d_storage_uuid, 2919 clsid2mime); 2920@@ -282,10 +271,10 @@ 2921 if (file_printf(ms, "%s%s", 2922 cdf_u16tos8(buf, ce[i].ce_namlen, ce[i].ce_name), 2923 i == cat->cat_num - 1 ? "]" : ", ") == -1) { 2924- free(cat); 2925+ efree(cat); 2926 return -1; 2927 } 2928- free(cat); 2929+ efree(cat); 2930 } else if (ms->flags & MAGIC_MIME_TYPE) { 2931 if (file_printf(ms, "application/CDFV2") == -1) 2932 return -1; 2933@@ -346,7 +335,7 @@ 2934 } 2935 2936 m = cdf_file_property_info(ms, info, count, root_storage); 2937- free(info); 2938+ efree(info); 2939 2940 return m == -1 ? -2 : m; 2941 } 2942@@ -656,11 +645,11 @@ 2943 cdf_zero_stream(&scn); 2944 cdf_zero_stream(&sst); 2945 out3: 2946- free(dir.dir_tab); 2947+ efree(dir.dir_tab); 2948 out2: 2949- free(ssat.sat_tab); 2950+ efree(ssat.sat_tab); 2951 out1: 2952- free(sat.sat_tab); 2953+ efree(sat.sat_tab); 2954 out0: 2955 /* If we handled it already, return */ 2956 if (i != -1) 2957diff -u libmagic.orig/softmagic.c libmagic/softmagic.c 2958--- libmagic.orig/softmagic.c 2023-07-27 21:40:12.000000000 +0200 2959+++ libmagic/softmagic.c 2024-02-15 19:28:46.036308654 +0100 2960@@ -45,7 +45,7 @@ 2961 #include <time.h> 2962 #include "der.h" 2963 2964-file_private int match(struct magic_set *, struct magic *, file_regex_t **, size_t, 2965+file_private int match(struct magic_set *, struct magic *, size_t, 2966 const struct buffer *, size_t, int, int, int, uint16_t *, 2967 uint16_t *, int *, int *, int *, int *, int *); 2968 file_private int mget(struct magic_set *, struct magic *, const struct buffer *, 2969@@ -54,7 +54,7 @@ 2970 uint16_t *, int *, int *, int *, int *, int *); 2971 file_private int msetoffset(struct magic_set *, struct magic *, struct buffer *, 2972 const struct buffer *, size_t, unsigned int); 2973-file_private int magiccheck(struct magic_set *, struct magic *, file_regex_t **); 2974+file_private int magiccheck(struct magic_set *, struct magic *); 2975 file_private int mprint(struct magic_set *, struct magic *); 2976 file_private int moffset(struct magic_set *, struct magic *, const struct buffer *, 2977 int32_t *); 2978@@ -133,7 +133,7 @@ 2979 } 2980 2981 for (ml = ms->mlist[0]->next; ml != ms->mlist[0]; ml = ml->next) { 2982- int ret = match(ms, ml->magic, ml->magic_rxcomp, ml->nmagic, b, 2983+ int ret = match(ms, ml->magic, ml->nmagic, b, 2984 0, mode, text, 0, indir_count, name_count, 2985 &printed_something, &need_separator, &firstline, 2986 NULL, NULL); 2987@@ -153,8 +153,8 @@ 2988 return rv; 2989 } 2990 2991-#define FILE_FMTDEBUG 2992-#ifdef FILE_FMTDEBUG 2993+ 2994+#if defined(FILE_FMTDEBUG) && defined(HAVE_FMTCHECK) 2995 #define F(a, b, c) file_fmtcheck((a), (b), (c), __FILE__, __LINE__) 2996 2997 file_private const char * __attribute__((__format_arg__(3))) 2998@@ -173,10 +173,14 @@ 2999 " with `%s'", file, line, desc, def); 3000 return ptr; 3001 } 3002-#else 3003+#elif defined(HAVE_FMTCHECK) 3004 #define F(a, b, c) fmtcheck((b), (c)) 3005+#else 3006+#define F(a, b, c) ((b)) 3007 #endif 3008 3009+/* NOTE this function has been kept an the state of 5.39 for BC. Observe 3010+ * further as the upgrade to 5.41 or above goes. */ 3011 /* 3012 * Go through the whole list, stopping if you find a match. Process all 3013 * the continuations of that match before returning. 3014@@ -205,7 +209,7 @@ 3015 * so that higher-level continuations are processed. 3016 */ 3017 file_private int 3018-match(struct magic_set *ms, struct magic *magic, file_regex_t **magic_rxcomp, 3019+match(struct magic_set *ms, struct magic *magic, 3020 size_t nmagic, const struct buffer *b, size_t offset, int mode, int text, 3021 int flip, uint16_t *indir_count, uint16_t *name_count, 3022 int *printed_something, int *need_separator, int *firstline, 3023@@ -233,10 +237,9 @@ 3024 for (magindex = 0; magindex < nmagic; magindex++) { 3025 int flush = 0; 3026 struct magic *m = &magic[magindex]; 3027- file_regex_t **m_rxcomp = &magic_rxcomp[magindex]; 3028 3029 if (m->type != FILE_NAME) 3030- if ((IS_STRING(m->type) && 3031+ if ((IS_LIBMAGIC_STRING(m->type) && 3032 #define FLT (STRING_BINTEST | STRING_TEXTTEST) 3033 ((text && (m->str_flags & FLT) == STRING_BINTEST) || 3034 (!text && (m->str_flags & FLT) == STRING_TEXTTEST))) || 3035@@ -272,7 +275,7 @@ 3036 *returnval = 1; 3037 } 3038 3039- switch (magiccheck(ms, m, m_rxcomp)) { 3040+ switch (magiccheck(ms, m)) { 3041 case -1: 3042 return -1; 3043 case 0: 3044@@ -334,7 +337,6 @@ 3045 while (magindex + 1 < nmagic && 3046 magic[magindex + 1].cont_level != 0) { 3047 m = &magic[++magindex]; 3048- m_rxcomp = &magic_rxcomp[magindex]; 3049 ms->line = m->lineno; /* for messages */ 3050 3051 if (cont_level < m->cont_level) 3052@@ -388,7 +390,7 @@ 3053 break; 3054 } 3055 3056- switch (flush ? 1 : magiccheck(ms, m, m_rxcomp)) { 3057+ switch (flush ? 1 : magiccheck(ms, m)) { 3058 case -1: 3059 return -1; 3060 case 0: 3061@@ -487,19 +489,25 @@ 3062 file_private int 3063 check_fmt(struct magic_set *ms, const char *fmt) 3064 { 3065- file_regex_t rx; 3066- int rc, rv = -1; 3067- const char* pat = "%[-0-9\\.]*s"; 3068+ pcre_cache_entry *pce; 3069+ int rv = -1; 3070+ zend_string *pattern; 3071 3072 if (strchr(fmt, '%') == NULL) 3073 return 0; 3074 3075- rc = file_regcomp(ms, &rx, pat, REG_EXTENDED|REG_NOSUB); 3076- if (rc == 0) { 3077- rc = file_regexec(ms, &rx, fmt, 0, 0, 0); 3078- rv = !rc; 3079+ pattern = ZSTR_INIT_LITERAL("~%[-0-9\\.]*s~", 0); 3080+ if ((pce = pcre_get_compiled_regex_cache_ex(pattern, 0)) == NULL) { 3081+ rv = -1; 3082+ } else { 3083+ pcre2_code *re = php_pcre_pce_re(pce); 3084+ pcre2_match_data *match_data = php_pcre_create_match_data(0, re); 3085+ if (match_data) { 3086+ rv = pcre2_match(re, (PCRE2_SPTR)fmt, strlen(fmt), 0, 0, match_data, php_pcre_mctx()) > 0; 3087+ php_pcre_free_match_data(match_data); 3088+ } 3089 } 3090- file_regfree(&rx); 3091+ zend_string_release_ex(pattern, 0); 3092 return rv; 3093 } 3094 3095@@ -517,7 +525,7 @@ 3096 3097 for (len = 0; len < n && str[len]; len++) 3098 continue; 3099- if ((copy = CAST(char *, malloc(len + 1))) == NULL) 3100+ if ((copy = CAST(char *, emalloc(len + 1))) == NULL) 3101 return NULL; 3102 (void)memcpy(copy, str, len); 3103 copy[len] = '\0'; 3104@@ -767,7 +775,7 @@ 3105 char *cp, *scp; 3106 int rval; 3107 3108- cp = strndup(RCAST(const char *, ms->search.s), 3109+ cp = estrndup(RCAST(const char *, ms->search.s), 3110 ms->search.rm_len); 3111 if (cp == NULL) { 3112 file_oomem(ms, ms->search.rm_len); 3113@@ -777,7 +785,7 @@ 3114 3115 rval = file_printf(ms, F(ms, desc, "%s"), file_printable(ms, 3116 sbuf, sizeof(sbuf), scp, ms->search.rm_len)); 3117- free(cp); 3118+ efree(cp); 3119 3120 if (rval == -1) 3121 return -1; 3122@@ -1565,7 +1573,7 @@ 3123 size_t len; 3124 *c = ms->c; 3125 len = c->len * sizeof(*c->li); 3126- ms->c.li = CAST(struct level_info *, malloc(len)); 3127+ ms->c.li = CAST(struct level_info *, emalloc(len)); 3128 if (ms->c.li == NULL) { 3129 ms->c = *c; 3130 return -1; 3131@@ -1577,7 +1585,7 @@ 3132 file_private void 3133 restore_cont(struct magic_set *ms, struct cont *c) 3134 { 3135- free(ms->c.li); 3136+ efree(ms->c.li); 3137 ms->c = *c; 3138 } 3139 3140@@ -1894,7 +1902,7 @@ 3141 for (mlp = ms->mlist[0]->next; mlp != ms->mlist[0]; 3142 mlp = mlp->next) 3143 { 3144- if ((rv = match(ms, mlp->magic, mlp->magic_rxcomp, 3145+ if ((rv = match(ms, mlp->magic, 3146 mlp->nmagic, &bb, 0, BINTEST, text, 0, indir_count, 3147 name_count, printed_something, need_separator, 3148 firstline, NULL, NULL)) != 0) 3149@@ -1913,15 +1921,15 @@ 3150 if ((ms->flags & MAGIC_NODESC) == 0 && 3151 file_printf(ms, F(ms, m->desc, "%u"), offset) == -1) 3152 { 3153- free(rbuf); 3154+ if (rbuf) efree(rbuf); 3155 return -1; 3156 } 3157 if (file_printf(ms, "%s", rbuf) == -1) { 3158- free(rbuf); 3159+ if (rbuf) efree(rbuf); 3160 return -1; 3161 } 3162 } 3163- free(rbuf); 3164+ if (rbuf) efree(rbuf); 3165 return rv; 3166 3167 case FILE_USE: 3168@@ -1948,7 +1956,7 @@ 3169 nfound_match = 0; 3170 (*name_count)++; 3171 eoffset = ms->eoffset; 3172- rv = match(ms, ml.magic, ml.magic_rxcomp, ml.nmagic, b, 3173+ rv = match(ms, ml.magic, ml.nmagic, b, 3174 offset + o, mode, text, flip, indir_count, name_count, 3175 printed_something, need_separator, firstline, returnval, 3176 &nfound_match); 3177@@ -2027,11 +2035,13 @@ 3178 } 3179 else if ((flags & STRING_COMPACT_WHITESPACE) && 3180 isspace(*a)) { 3181+ /* XXX Dirty. The data and the pattern is what is causing this. 3182+ Revert _i for the next port and see if it still matters. */ 3183+ uint32_t _i = 0; 3184 a++; 3185- if (isspace(*b)) { 3186- b++; 3187+ if (isspace(*b++)) { 3188 if (!isspace(*a)) 3189- while (b < eb && isspace(*b)) 3190+ while (EXPECTED(_i++ < 2048) && b < eb && isspace(*b)) 3191 b++; 3192 } 3193 else { 3194@@ -2071,29 +2081,8 @@ 3195 return file_strncmp(a, b, len, maxlen, flags); 3196 } 3197 3198-file_private file_regex_t * 3199-alloc_regex(struct magic_set *ms, struct magic *m) 3200-{ 3201- int rc; 3202- file_regex_t *rx = CAST(file_regex_t *, malloc(sizeof(*rx))); 3203- 3204- if (rx == NULL) { 3205- file_error(ms, errno, "can't allocate %" SIZE_T_FORMAT 3206- "u bytes", sizeof(*rx)); 3207- return NULL; 3208- } 3209- 3210- rc = file_regcomp(ms, rx, m->value.s, REG_EXTENDED | REG_NEWLINE | 3211- ((m->str_flags & STRING_IGNORE_CASE) ? REG_ICASE : 0)); 3212- if (rc == 0) 3213- return rx; 3214- 3215- free(rx); 3216- return NULL; 3217-} 3218- 3219 file_private int 3220-magiccheck(struct magic_set *ms, struct magic *m, file_regex_t **m_cache) 3221+magiccheck(struct magic_set *ms, struct magic *m) 3222 { 3223 uint64_t l = m->value.q; 3224 uint64_t v; 3225@@ -2247,28 +2236,14 @@ 3226 slen = MIN(m->vallen, sizeof(m->value.s)); 3227 l = 0; 3228 v = 0; 3229- if ((ms->flags & MAGIC_DEBUG) != 0) { 3230- size_t xlen = ms->search.s_len > 100 ? 100 3231- : ms->search.s_len; 3232- 3233- fprintf(stderr, "search: ["); 3234- file_showstr(stderr, ms->search.s, xlen); 3235- fprintf(stderr, "%s] for [", ms->search.s_len == xlen 3236- ? "" : "..."); 3237- file_showstr(stderr, m->value.s, slen); 3238- } 3239 #ifdef HAVE_MEMMEM 3240 if (slen > 0 && m->str_flags == 0) { 3241 const char *found; 3242 idx = m->str_range + slen; 3243 if (m->str_range == 0 || ms->search.s_len < idx) 3244 idx = ms->search.s_len; 3245- found = CAST(const char *, memmem(ms->search.s, idx, 3246- m->value.s, slen)); 3247- if ((ms->flags & MAGIC_DEBUG) != 0) { 3248- fprintf(stderr, "] %sfound\n", 3249- found ? "" : "not "); 3250- } 3251+ found = CAST(const char *, php_memnstr(ms->search.s, 3252+ m->value.s, slen, ms->search.s + idx)); 3253 if (!found) { 3254 v = 1; 3255 break; 3256@@ -2294,61 +2269,79 @@ 3257 break; 3258 } 3259 } 3260- if ((ms->flags & MAGIC_DEBUG) != 0) { 3261- fprintf(stderr, "] %sfound\n", v == 0 ? "" : "not "); 3262- } 3263 break; 3264 } 3265 case FILE_REGEX: { 3266- int rc; 3267- file_regex_t *rx = *m_cache; 3268- const char *search; 3269- regmatch_t pmatch; 3270- size_t slen = ms->search.s_len; 3271- char *copy; 3272+ zend_string *pattern; 3273+ uint32_t options = 0; 3274+ pcre_cache_entry *pce; 3275 3276- if (ms->search.s == NULL) 3277- return 0; 3278+ options |= PCRE2_MULTILINE; 3279 3280- if (rx == NULL) { 3281- rx = *m_cache = alloc_regex(ms, m); 3282- if (rx == NULL) 3283- return -1; 3284+ if (m->str_flags & STRING_IGNORE_CASE) { 3285+ options |= PCRE2_CASELESS; 3286 } 3287- l = 0; 3288- if (slen != 0) { 3289- copy = CAST(char *, malloc(slen)); 3290- if (copy == NULL) { 3291- file_error(ms, errno, 3292- "can't allocate %" SIZE_T_FORMAT "u bytes", 3293- slen); 3294- return -1; 3295- } 3296- memcpy(copy, ms->search.s, slen); 3297- copy[--slen] = '\0'; 3298- search = copy; 3299- } else { 3300- search = CCAST(char *, ""); 3301- copy = NULL; 3302- } 3303- rc = file_regexec(ms, rx, RCAST(const char *, search), 3304- 1, &pmatch, 0); 3305- free(copy); 3306- switch (rc) { 3307- case 0: 3308- ms->search.s += CAST(int, pmatch.rm_so); 3309- ms->search.offset += CAST(size_t, pmatch.rm_so); 3310- ms->search.rm_len = CAST(size_t, 3311- pmatch.rm_eo - pmatch.rm_so); 3312- v = 0; 3313- break; 3314 3315- case REG_NOMATCH: 3316- v = 1; 3317- break; 3318+ pattern = convert_libmagic_pattern((char *)m->value.s, m->vallen, options); 3319 3320- default: 3321+ l = v = 0; 3322+ if ((pce = pcre_get_compiled_regex_cache(pattern)) == NULL) { 3323+ zend_string_release(pattern); 3324 return -1; 3325+ } else { 3326+ /* pce now contains the compiled regex */ 3327+ zval retval; 3328+ zval subpats; 3329+ zend_string *haystack; 3330+ 3331+ ZVAL_NULL(&retval); 3332+ ZVAL_NULL(&subpats); 3333+ 3334+ /* Cut the search len from haystack, equals to REG_STARTEND */ 3335+ haystack = zend_string_init(ms->search.s, ms->search.s_len, 0); 3336+ 3337+ /* match v = 0, no match v = 1 */ 3338+ php_pcre_match_impl(pce, haystack, &retval, &subpats, 0, PREG_OFFSET_CAPTURE, 0); 3339+ /* Free haystack */ 3340+ zend_string_release(haystack); 3341+ 3342+ if (Z_LVAL(retval) < 0) { 3343+ zval_ptr_dtor(&subpats); 3344+ zend_string_release(pattern); 3345+ return -1; 3346+ } else if ((Z_LVAL(retval) > 0) && (Z_TYPE(subpats) == IS_ARRAY)) { 3347+ /* Need to fetch global match which equals pmatch[0] */ 3348+ zval *pzval; 3349+ HashTable *ht = Z_ARRVAL(subpats); 3350+ if ((pzval = zend_hash_index_find(ht, 0)) != NULL && Z_TYPE_P(pzval) == IS_ARRAY) { 3351+ /* If everything goes according to the master plan 3352+ tmpcopy now contains two elements: 3353+ 0 = the match 3354+ 1 = starting position of the match */ 3355+ zval *match, *offset; 3356+ if ((match = zend_hash_index_find(Z_ARRVAL_P(pzval), 0)) && 3357+ (offset = zend_hash_index_find(Z_ARRVAL_P(pzval), 1))) { 3358+ if (Z_TYPE_P(match) != IS_STRING && Z_TYPE_P(offset) != IS_LONG) { 3359+ goto error_out; 3360+ } 3361+ ms->search.s += Z_LVAL_P(offset); /* this is where the match starts */ 3362+ ms->search.offset += Z_LVAL_P(offset); /* this is where the match starts as size_t */ 3363+ ms->search.rm_len = Z_STRLEN_P(match) /* This is the length of the matched pattern */; 3364+ v = 0; 3365+ } else { 3366+ goto error_out; 3367+ } 3368+ } else { 3369+error_out: 3370+ zval_ptr_dtor(&subpats); 3371+ zend_string_release(pattern); 3372+ return -1; 3373+ } 3374+ } else { 3375+ v = 1; 3376+ } 3377+ zval_ptr_dtor(&subpats); 3378+ zend_string_release(pattern); 3379 } 3380 break; 3381 } 3382