From ae4928a246d14c0a23133e279e92acf73abaca8f Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 30 Jul 2025 22:40:23 +0200 Subject: [PATCH 1/3] Rename phar number parser to avoid confusion --- ext/phar/tar.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ext/phar/tar.c b/ext/phar/tar.c index 550183746a2c..a5a02a829f25 100644 --- a/ext/phar/tar.c +++ b/ext/phar/tar.c @@ -20,7 +20,7 @@ #include "phar_internal.h" #include "ext/standard/php_string.h" /* For php_stristr() */ -static uint32_t phar_tar_number(const char *buf, size_t len) /* {{{ */ +static uint32_t phar_tar_oct_number(const char *buf, size_t len) /* {{{ */ { uint32_t num = 0; size_t i = 0; @@ -103,7 +103,7 @@ static uint32_t phar_tar_checksum(char *buf, size_t len) /* {{{ */ bool phar_is_tar(char *buf, char *fname) /* {{{ */ { tar_header *header = (tar_header *) buf; - uint32_t checksum = phar_tar_number(header->checksum, sizeof(header->checksum)); + uint32_t checksum = phar_tar_oct_number(header->checksum, sizeof(header->checksum)); bool is_tar; char save[sizeof(header->checksum)], *bname; @@ -251,7 +251,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch pos = php_stream_tell(fp); hdr = (tar_header*) buf; - sum1 = phar_tar_number(hdr->checksum, sizeof(hdr->checksum)); + sum1 = phar_tar_oct_number(hdr->checksum, sizeof(hdr->checksum)); if (sum1 == 0 && phar_tar_checksum(buf, sizeof(buf)) == 0) { break; } @@ -268,7 +268,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch } size = entry.uncompressed_filesize = entry.compressed_filesize = - phar_tar_number(hdr->size, sizeof(hdr->size)); + phar_tar_oct_number(hdr->size, sizeof(hdr->size)); /* skip global/file headers (pax) */ if (!old && (hdr->typeflag == TAR_GLOBAL_HDR || hdr->typeflag == TAR_FILE_HDR)) { @@ -343,7 +343,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch } hdr = (tar_header*) buf; - sum1 = phar_tar_number(hdr->checksum, sizeof(hdr->checksum)); + sum1 = phar_tar_oct_number(hdr->checksum, sizeof(hdr->checksum)); if (sum1 == 0 && phar_tar_checksum(buf, sizeof(buf)) == 0) { break; @@ -475,12 +475,12 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch return FAILURE; } - uint32_t entry_mode = phar_tar_number(hdr->mode, sizeof(hdr->mode)); + uint32_t entry_mode = phar_tar_oct_number(hdr->mode, sizeof(hdr->mode)); entry.tar_type = ((old & (hdr->typeflag == '\0')) ? TAR_FILE : hdr->typeflag); entry.offset = entry.offset_abs = pos; /* header_offset unused in tar */ entry.fp_type = PHAR_FP; entry.flags = entry_mode & PHAR_ENT_PERM_MASK; - entry.timestamp = phar_tar_number(hdr->mtime, sizeof(hdr->mtime)); + entry.timestamp = phar_tar_oct_number(hdr->mtime, sizeof(hdr->mtime)); entry.is_persistent = myphar->is_persistent; if (old && entry.tar_type == TAR_FILE && S_ISDIR(entry_mode)) { From 8505e13abc06f4825977ea780408345ede4c2d61 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 30 Jul 2025 22:41:27 +0200 Subject: [PATCH 2/3] Unify all phar tar bail paths --- ext/phar/tar.c | 64 +++++++++++++------------------------------------- 1 file changed, 16 insertions(+), 48 deletions(-) diff --git a/ext/phar/tar.c b/ext/phar/tar.c index a5a02a829f25..f954c775ce28 100644 --- a/ext/phar/tar.c +++ b/ext/phar/tar.c @@ -325,9 +325,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch if (error) { spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname); } - php_stream_close(fp); - phar_destroy_phar_data(myphar); - return FAILURE; + goto bail; } } @@ -337,9 +335,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch if (error) { spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname); } - php_stream_close(fp); - phar_destroy_phar_data(myphar); - return FAILURE; + goto bail; } hdr = (tar_header*) buf; @@ -365,9 +361,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch if (error) { spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (invalid entry size)", fname); } - php_stream_close(fp); - phar_destroy_phar_data(myphar); - return FAILURE; + goto bail; } entry.filename = zend_string_alloc(entry.uncompressed_filesize, myphar->is_persistent); if (myphar->is_persistent) { @@ -381,9 +375,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch if (error) { spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname); } - php_stream_close(fp); - phar_destroy_phar_data(myphar); - return FAILURE; + goto bail; } /* skip blank stuff */ @@ -396,9 +388,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch if (error) { spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname); } - php_stream_close(fp); - phar_destroy_phar_data(myphar); - return FAILURE; + goto bail; } read = php_stream_read(fp, buf, sizeof(buf)); @@ -408,9 +398,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch if (error) { spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname); } - php_stream_close(fp); - phar_destroy_phar_data(myphar); - return FAILURE; + goto bail; } continue; } else if (!last_was_longlink && !old && hdr->prefix[0] != 0) { @@ -470,9 +458,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (checksum mismatch of file \"%s\")", fname, ZSTR_VAL(entry.filename)); } zend_string_release_ex(entry.filename, myphar->is_persistent); - php_stream_close(fp); - phar_destroy_phar_data(myphar); - return FAILURE; + goto bail; } uint32_t entry_mode = phar_tar_oct_number(hdr->mode, sizeof(hdr->mode)); @@ -503,9 +489,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file - hard link to non-existent file \"%.*s\"", fname, (int)linkname_len, hdr->linkname); } zend_string_release_ex(entry.filename, myphar->is_persistent); - php_stream_close(fp); - phar_destroy_phar_data(myphar); - return FAILURE; + goto bail; } entry.link = estrndup(hdr->linkname, linkname_len); } else if (entry.tar_type == TAR_SYMLINK) { @@ -525,9 +509,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch if (error) { spprintf(error, 4096, "phar error: tar-based phar \"%s\" has invalid metadata in magic file \"%s\"", fname, ZSTR_VAL(entry.filename)); } - php_stream_close(fp); - phar_destroy_phar_data(myphar); - return FAILURE; + goto bail; } } @@ -537,9 +519,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch if (error) { spprintf(error, 4096, "phar error: tar-based phar \"%s\" has alias that is larger than 511 bytes, cannot process", fname); } - php_stream_close(fp); - phar_destroy_phar_data(myphar); - return FAILURE; + goto bail; } read = php_stream_read(fp, buf, size); @@ -558,9 +538,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch spprintf(error, 4096, "phar error: invalid alias \"%s\" in tar-based phar \"%s\"", buf, fname); } - php_stream_close(fp); - phar_destroy_phar_data(myphar); - return FAILURE; + goto bail; } actual_alias = pestrndup(buf, size, myphar->is_persistent); @@ -572,9 +550,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch spprintf(error, 4096, "phar error: Unable to read alias from tar-based phar \"%s\"", fname); } - php_stream_close(fp); - phar_destroy_phar_data(myphar); - return FAILURE; + goto bail; } } @@ -588,9 +564,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch if (error) { spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname); } - php_stream_close(fp); - phar_destroy_phar_data(myphar); - return FAILURE; + goto bail; } } @@ -605,9 +579,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch if (error) { spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname); } - php_stream_close(fp); - phar_destroy_phar_data(myphar); - return FAILURE; + goto bail; } } @@ -619,12 +591,10 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch /* ensure signature set */ if (!myphar->is_data && PHAR_G(require_hash) && !myphar->signature) { - php_stream_close(fp); - phar_destroy_phar_data(myphar); if (error) { spprintf(error, 0, "tar-based phar \"%s\" does not have a signature", fname); } - return FAILURE; + goto bail; } myphar->fname = pestrndup(fname, fname_len, myphar->is_persistent); @@ -651,9 +621,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch if (error) { spprintf(error, 4096, "phar error: Unable to add tar-based phar \"%s\" to phar registry", fname); } - php_stream_close(fp); - phar_destroy_phar_data(myphar); - return FAILURE; + goto bail; } myphar = actual; From 22c750cc4e9b1532f9173ca99d3ef06692adec09 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 30 Jul 2025 22:41:36 +0200 Subject: [PATCH 3/3] Parse PAX header and extract path --- ext/phar/tar.c | 203 ++++++++++++++++-- .../tar/files/gh19311/global_hdrcharset.tar | Bin 0 -> 10240 bytes .../files/gh19311/global_path_override.tar | Bin 0 -> 10240 bytes .../tar/files/gh19311/local_hdrcharset.tar | Bin 0 -> 10240 bytes .../tar/files/gh19311/path_edge_case.tar | Bin 0 -> 10240 bytes .../files/gh19311/pax_local_path_override.tar | Bin 0 -> 10240 bytes ext/phar/tests/tar/pax/gh19311.phpt | 15 ++ ext/phar/tests/tar/pax/global_hdrcharset.phpt | 16 ++ .../tests/tar/pax/global_path_override.phpt | 16 ++ ext/phar/tests/tar/pax/local_hdrcharset.phpt | 16 ++ ext/phar/tests/tar/pax/path_edge_case.phpt | 16 ++ 11 files changed, 267 insertions(+), 15 deletions(-) create mode 100644 ext/phar/tests/tar/files/gh19311/global_hdrcharset.tar create mode 100644 ext/phar/tests/tar/files/gh19311/global_path_override.tar create mode 100644 ext/phar/tests/tar/files/gh19311/local_hdrcharset.tar create mode 100644 ext/phar/tests/tar/files/gh19311/path_edge_case.tar create mode 100644 ext/phar/tests/tar/files/gh19311/pax_local_path_override.tar create mode 100644 ext/phar/tests/tar/pax/gh19311.phpt create mode 100644 ext/phar/tests/tar/pax/global_hdrcharset.phpt create mode 100644 ext/phar/tests/tar/pax/global_path_override.phpt create mode 100644 ext/phar/tests/tar/pax/local_hdrcharset.phpt create mode 100644 ext/phar/tests/tar/pax/path_edge_case.phpt diff --git a/ext/phar/tar.c b/ext/phar/tar.c index f954c775ce28..f777953f9797 100644 --- a/ext/phar/tar.c +++ b/ext/phar/tar.c @@ -198,6 +198,128 @@ static zend_result phar_tar_process_metadata(phar_entry_info *entry, php_stream } /* }}} */ +/* Parses a PAX header and callbacks into `cb` for each valid key-value pair, + * passing along a `ctx` pointer to use for storing data when desired. */ +static const char *phar_parse_pax_header(char *ptr, uint32_t size, void *ctx, const char *(*cb)(const char *, uint32_t, const char *, void *)) +{ + const char *pax_data_end = ptr + size; + while (ptr < pax_data_end) { + /* Format: "%d %s=%s\n" */ + char *endptr; + char *blank = memchr(ptr, ' ', pax_data_end - ptr); + if (!blank) { + break; + } + *blank = '\0'; + size_t kv_size = strtoull(ptr, &endptr, 10); + /* blank, non-empty keyword, equals, newline terminator */ + if (endptr != blank || kv_size < 4 || kv_size > pax_data_end - ptr) { + break; + } + + /* Check terminator */ + char *record_end = ptr + kv_size; + if (record_end[-1] != '\n') { + break; + } + + /* Validate keyword */ + const char *key = blank + 1; + const char *equals = memchr(key, '=', record_end - key); + if (!equals || key == equals) { + break; + } + + const char *err = cb(key, equals - key, record_end, ctx); + if (err) { + return err; + } + + ptr = record_end; + } + + return NULL; +} + +struct phar_pax_local { + zend_string *filename_override; + bool is_persistent; +}; + +static const char *phar_pax_parse_path(const char *key, uint32_t key_len, const char *record_end, struct phar_pax_local *pax) +{ + const char *filename_start = key + key_len + 1; + size_t pax_local_filename_len = record_end - filename_start; + if (pax_local_filename_len <= 1) { + return "invalid path length"; + } + + /* strip '\n' */ + pax_local_filename_len--; + /* Ending '/' stripping */ + if (filename_start[pax_local_filename_len - 1] == '/') { + pax_local_filename_len--; + } + + /* Last one takes precedence if multiple are provided */ + if (pax->filename_override) { + pefree(pax->filename_override, pax->is_persistent); + pax->filename_override = NULL; + } + + pax->filename_override = zend_string_init(filename_start, pax_local_filename_len, pax->is_persistent); + if (pax->is_persistent) { + GC_MAKE_PERSISTENT_LOCAL(pax_local_filename); + } + + return NULL; +} + +static bool phar_pax_parse_hdrcharset(const char *key, uint32_t key_len, const char *record_end) +{ + const char *value = key + key_len + 1; + size_t value_len = record_end - value; + + if ((value_len == strlen("BINARY") && strncmp(value, "BINARY", strlen("BINARY")) == 0) +#if 0 /* TODO: support UTF-8 to local locale conversion? */ + || (value_len == strlen("ISO-IR 10646 2000 UTF-8") && strncmp(value, "ISO-IR 10646 2000 UTF-8", strlen("ISO-IR 10646 2000 UTF-8")) == 0) +#endif + ) { + return true; + } else { + return false; + } +} + +static const char *phar_pax_local_cb(const char *key, uint32_t key_len, const char *record_end, void *ctx) +{ + if (key_len == strlen("hdrcharset") && memcmp(key, "hdrcharset", strlen("hdrcharset")) == 0) { + if (!phar_pax_parse_hdrcharset(key, key_len, record_end)) { + return "invalid header character set"; + } + } else if (key_len == strlen("path") && memcmp(key, "path", strlen("path")) == 0) { + return phar_pax_parse_path(key, key_len, record_end, ctx); + } + + return NULL; +} + +static const char *phar_pax_global_cb(const char *key, uint32_t key_len, const char *record_end, void *ctx) +{ + if (key_len == strlen("hdrcharset") && memcmp(key, "hdrcharset", strlen("hdrcharset")) == 0) { + if (!phar_pax_parse_hdrcharset(key, key_len, record_end)) { + return "invalid header character set"; + } + } else if (key_len == strlen("path") && memcmp(key, "path", strlen("path")) == 0) { + /* Some application support this (e.g. GNU tar), others don't (e.g. GNOME file roller). + * This just adds needless complications. */ + *(bool *) ctx = true; + return "unsupported global path override"; + } + + return NULL; +} + zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, char *alias, size_t alias_len, phar_archive_data** pphar, uint32_t compression, char **error) /* {{{ */ { char buf[512], *actual_alias = NULL, *p; @@ -206,7 +328,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch tar_header *hdr; uint32_t sum1, sum2, size, old; phar_archive_data *myphar, *actual; - bool last_was_longlink = false; + bool last_was_name_override = false; size_t linkname_len; if (error) { @@ -270,13 +392,62 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch size = entry.uncompressed_filesize = entry.compressed_filesize = phar_tar_oct_number(hdr->size, sizeof(hdr->size)); - /* skip global/file headers (pax) */ - if (!old && (hdr->typeflag == TAR_GLOBAL_HDR || hdr->typeflag == TAR_FILE_HDR)) { - size = (size+511)&~511; - goto next; + /* Process global/file pax header: https://pubs.opengroup.org/onlinepubs/9799919799/utilities/pax.html */ + if (!old && hdr->typeflag == TAR_GLOBAL_HDR) { + size = (size + 511) & ~511; + char *pax_data = emalloc(size); + + if (UNEXPECTED(php_stream_read(fp, pax_data, size) != size)) { + efree(pax_data); + goto truncated; + } + + bool hard_fail = false; + const char *err = phar_parse_pax_header(pax_data, size, &hard_fail, phar_pax_global_cb); + efree(pax_data); + + if (err) { + if (hard_fail) { + /* Likely maliciously formed tar. */ + spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (invalid global pax header: %s)", fname, err); + goto bail; + } else { + /* Previous versions of PHP just ignored the PAX headers, so let's not hard fail here. */ + php_error_docref(NULL, E_NOTICE, "Global PAX header component not understood: %s", err); + } + } + + goto next_no_seek; + } else if (!old && hdr->typeflag == TAR_FILE_HDR) { + size = (size + 511) & ~511; + char *pax_data = emalloc(size); + + if (UNEXPECTED(php_stream_read(fp, pax_data, size) != size)) { + efree(pax_data); + goto truncated; + } + + struct phar_pax_local pax; + pax.filename_override = entry.filename; + pax.is_persistent = myphar->is_persistent; + const char *err = phar_parse_pax_header(pax_data, size, &pax, phar_pax_local_cb); + efree(pax_data); + + if (pax.filename_override) { + last_was_name_override = true; + entry.filename = pax.filename_override; + } + + if (err) { + /* Previous versions of PHP just ignored the PAX headers, so let's not hard fail here. */ + php_error_docref(NULL, E_NOTICE, "File PAX header component not understood: %s", err); + } + + goto next_no_seek; } - if (((!old && hdr->prefix[0] == 0) || old) && zend_strnlen(hdr->name, 100) == sizeof(".phar/signature.bin")-1 && !strncmp(hdr->name, ".phar/signature.bin", sizeof(".phar/signature.bin")-1)) { + if ((entry.filename && zend_string_equals_literal(entry.filename, ".phar/signature.bin")) + || (((!old && hdr->prefix[0] == 0) || old) && !strcmp(hdr->name, ".phar/signature.bin"))) { zend_off_t curloc; size_t sig_len; @@ -352,8 +523,8 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch goto bail; } - if (!last_was_longlink && hdr->typeflag == 'L') { - last_was_longlink = true; + if (!last_was_name_override && hdr->typeflag == 'L') { + last_was_name_override = true; /* support the ././@LongLink system for storing long filenames */ /* Check for overflow - bug 61065 */ @@ -401,7 +572,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch goto bail; } continue; - } else if (!last_was_longlink && !old && hdr->prefix[0] != 0) { + } else if (!last_was_name_override && !old && hdr->prefix[0] != 0) { char name[256]; int i, j; @@ -430,7 +601,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch if (myphar->is_persistent) { GC_MAKE_PERSISTENT_LOCAL(entry.filename); } - } else if (!last_was_longlink) { + } else if (!last_was_name_override) { /* calculate strlen, which can be no longer than 100 */ uint32_t filename_len; for (filename_len = 0; filename_len < 100; filename_len++) { @@ -449,7 +620,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch GC_MAKE_PERSISTENT_LOCAL(entry.filename); } } - last_was_longlink = false; + last_was_name_override = false; phar_add_virtual_dirs(myphar, ZSTR_VAL(entry.filename), ZSTR_LEN(entry.filename)); @@ -499,21 +670,22 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch newentry = zend_hash_update_mem(&myphar->manifest, entry.filename, &entry, sizeof(phar_entry_info)); ZEND_ASSERT(newentry != NULL); + entry.filename = NULL; if (entry.is_persistent) { ++entry.manifest_pos; } - if (zend_string_starts_with_literal(entry.filename, ".phar/.metadata")) { + if (zend_string_starts_with_literal(newentry->filename, ".phar/.metadata")) { if (FAILURE == phar_tar_process_metadata(newentry, fp)) { if (error) { - spprintf(error, 4096, "phar error: tar-based phar \"%s\" has invalid metadata in magic file \"%s\"", fname, ZSTR_VAL(entry.filename)); + spprintf(error, 4096, "phar error: tar-based phar \"%s\" has invalid metadata in magic file \"%s\"", fname, ZSTR_VAL(newentry->filename)); } goto bail; } } - if (!actual_alias && zend_string_equals_literal(entry.filename, ".phar/alias.txt")) { + if (!actual_alias && zend_string_equals_literal(newentry->filename, ".phar/alias.txt")) { /* found explicit alias */ if (size > 511) { if (error) { @@ -557,9 +729,9 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch size = (size+511)&~511; if (((hdr->typeflag == '\0') || (hdr->typeflag == TAR_FILE)) && size > 0) { -next: /* this is not good enough - seek succeeds even on truncated tars */ php_stream_seek(fp, size, SEEK_CUR); +next_no_seek: if ((uint32_t)php_stream_tell(fp) > totalsize) { if (error) { spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname); @@ -576,6 +748,7 @@ zend_result phar_parse_tarfile(php_stream* fp, char *fname, size_t fname_len, ch read = php_stream_read(fp, buf, sizeof(buf)); if (read != sizeof(buf)) { +truncated: if (error) { spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file (truncated)", fname); } diff --git a/ext/phar/tests/tar/files/gh19311/global_hdrcharset.tar b/ext/phar/tests/tar/files/gh19311/global_hdrcharset.tar new file mode 100644 index 0000000000000000000000000000000000000000..051db50833d333855e4d554838611615f0be283c GIT binary patch literal 10240 zcmeIz-)h1z6bA5I`xJSC_T)dk@N&!x!M#GJVG6C2HiJICi6C2*x|>c0{c_QeoDxoc z@R2e$r}DM_eE0P#_+25`^n=o{TC+T-aXS-9&4eLmq)s2hNQk_}Kc;Wx{=}~?`Zl$6 zUzx>@B);FZ+r4kQ5SOc$^?I|I#l>;Si$GDn`93Er#JZ|%^gk}6GZ}K(&$3v*QLEFQ{Z}s8dSU~^+5P$##AOHafKmY;| gfB*y_009U<00Izz00bZa0SG_<0uX=z1fD8z2Bt$;asU7T literal 0 HcmV?d00001 diff --git a/ext/phar/tests/tar/files/gh19311/global_path_override.tar b/ext/phar/tests/tar/files/gh19311/global_path_override.tar new file mode 100644 index 0000000000000000000000000000000000000000..5385d47f22c04002fe837bbeae3d550c5a601299 GIT binary patch literal 10240 zcmeH~L2kn!5JkPtDSQHZ00;0Q>vq{Ikk)M@#ZBb6QqBxH zUmur!yDuNMyS3XsHtwYm+4X}sbX8@(<%nA%DKoJovm{bx$>W3|p|kw$`lU=){5O^}6Fvpj*4I#VodsP5uxl$|ra9%5Sw>J2g|$kXy0W#;J_p%gZVVdz zTO^Q3^1)U|`WI~S-v5Wzr#NE$la}oNf8xo5{y#R&_7IdEb}r?^(Rb5x@cX+ts}zL> z{?9kS6z}i~Kkxtad;jW`r2oP9ht{V!#{PfOzZL}l441@UPZit_D?Ntf{W0hptlfgphKh*E9UaGNIDc8PHo+>NGbkQDUSrM(LR4Hj7Q4kI{zD@r&WLbSu$)7p}bx4>ul~ zQ`??5Yk52GRLVtryL(rRam>asg?eAl8BbYHRm9A5DgS0yEB%*Dt~~#Z^M25;A^2{a y?E|ne0tg_000IagfB*srAb_MJLdTB1f>0qt3L&-N@f(p05xOPq;QtNE(_rE+e7e!i z_3q-$yN91-momBJ%WO<*mc8_d%zbC9sJP456o*bGG5L(^J&bL^51qRQ9sFK<@w+6H**vM2q1s}0tg_000Iag hfB*srAbT$yz=PC>Q^#v)hS(ykGvB*Gj?CNbfHM)n0ID4HC` z8NR=leQ8u-f2qIK(^@H-Y)!h=3oHeab2^uJN;#d0nVicPYgHYqz|P94vo1T<)3;9x z*;7rdP5I;wvvZ`EoIBoQ$&dW6YG-n#&3{5I|M?yMrPF1_|18y;vSY1ZT(Z|K|I|~* z|BZBDcCm`z(~TZDBj;d0{b!Pa{tra`y3cRXf8z9?%|QRJgZQCab@+cG{dk$c@!wDX zIYJ!tKSbd4_`i_}zEZQcxuD)1WNLeTR`Aw;f~1hJ{tw}Q(Eku9KkgV!QoAjGQtSU& z(%+I5y!D@8L>cIRh^X=Qe%ZVafc}T@ zKj?o5lpl8tZ~pg^{(N@u*MA`>1^o{ZH6#1KksVZ=uk+*a(Ix$-ME*YiqljbB{}Aqv z?2XIBt@{=u2SV-r`0P4zYJgetPathname(), "\n"; +} + +?> +--EXPECTF-- +phar://%s/pax_local_path_override.tar/a-very-long-path/to-a-file/with-a-very-long-name/in-a-deep-directory-structure/a-php-file-with-a-very-long-name.php diff --git a/ext/phar/tests/tar/pax/global_hdrcharset.phpt b/ext/phar/tests/tar/pax/global_hdrcharset.phpt new file mode 100644 index 000000000000..a9917e9d2025 --- /dev/null +++ b/ext/phar/tests/tar/pax/global_hdrcharset.phpt @@ -0,0 +1,16 @@ +--TEST-- +Global hdrcharset +--EXTENSIONS-- +phar +--FILE-- +getPathname(), "\n"; +} + +?> +--EXPECTF-- +Notice: PharData::__construct(): Global PAX header component not understood: invalid header character set in %s on line %d +phar://%s/global_hdrcharset.tar/example.txt diff --git a/ext/phar/tests/tar/pax/global_path_override.phpt b/ext/phar/tests/tar/pax/global_path_override.phpt new file mode 100644 index 000000000000..ff28282fa6f1 --- /dev/null +++ b/ext/phar/tests/tar/pax/global_path_override.phpt @@ -0,0 +1,16 @@ +--TEST-- +Global path override with PAX header +--EXTENSIONS-- +phar +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECTF-- +phar error: "%s" is a corrupted tar file (invalid global pax header: unsupported global path override) diff --git a/ext/phar/tests/tar/pax/local_hdrcharset.phpt b/ext/phar/tests/tar/pax/local_hdrcharset.phpt new file mode 100644 index 000000000000..53a0f7c6f437 --- /dev/null +++ b/ext/phar/tests/tar/pax/local_hdrcharset.phpt @@ -0,0 +1,16 @@ +--TEST-- +Local hdrcharset +--EXTENSIONS-- +phar +--FILE-- +getPathname(), "\n"; +} + +?> +--EXPECTF-- +Notice: PharData::__construct(): File PAX header component not understood: invalid header character set in %s on line %d +phar://%s/local_hdrcharset.tar/example.txt diff --git a/ext/phar/tests/tar/pax/path_edge_case.phpt b/ext/phar/tests/tar/pax/path_edge_case.phpt new file mode 100644 index 000000000000..e3e06463b400 --- /dev/null +++ b/ext/phar/tests/tar/pax/path_edge_case.phpt @@ -0,0 +1,16 @@ +--TEST-- +Path edge case +--EXTENSIONS-- +phar +--FILE-- +getPathname(), "\n"; +} + +?> +--EXPECTF-- +Notice: PharData::__construct(): File PAX header component not understood: invalid path length in %s on line %d +phar://%s/path_edge_case.tar/example.txt