Merge pull request #3257 from R4mbb/fix-pax-all-slash-pathname

pax: handle all-slash pathnames in USTAR name splitting
This commit is contained in:
Dustin L. Howett authored and GitHub committed 2026-07-09 10:53:22 -05:00
commit 8d62a0512a
2 files changed
+51

No files matched your search

+20
View File
@@ -1607,6 +1607,26 @@ build_ustar_entry_name(char *dest, const char *src, size_t src_length,
}
break;
}
/*
* Pathological case: after trimming trailing '/' characters and
* '/.' path elements, there is no filename component left. This
* happens for pathnames made entirely of '/' characters. Do not
* attempt to compute filename_end - 1 in that case, which would
* move the filename pointer in front of the input buffer and read
* one byte out of bounds. Emit a root-like ustar name instead.
*/
if (filename_end == src) {
p = dest;
if (insert != NULL) {
strcpy(p, insert);
p += strlen(insert);
}
*p++ = '/';
*p = '\0';
return (dest);
}
if (need_slash)
suffix_length--;
/* Find start of filename. */
+31
View File
@@ -36,6 +36,7 @@ DEFINE_TEST(test_write_format_pax)
int i;
char nulls[1024];
int64_t offset, length;
char long_slashes[300 + 1];
buff = malloc(buffsize); /* million bytes of work area */
assert(buff != NULL);
@@ -125,6 +126,23 @@ DEFINE_TEST(test_write_format_pax)
archive_entry_free(ae);
assertEqualIntA(a, 8, archive_write_data(a, "12345678", 9));
/*
* A pathname made entirely of '/' characters used to trigger an
* out-of-bounds read in the pax writer when the pathname was long
* enough to require USTAR name splitting.
*/
memset(long_slashes, '/', 300);
long_slashes[300] = '\0';
assert((ae = archive_entry_new()) != NULL);
archive_entry_set_atime(ae, 2, 20);
archive_entry_set_ctime(ae, 4, 40);
archive_entry_set_mtime(ae, 5, 50);
archive_entry_copy_pathname(ae, long_slashes);
archive_entry_set_mode(ae, S_IFREG | 0644);
archive_entry_set_size(ae, 0);
assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
archive_entry_free(ae);
/*
* XXX TODO XXX Archive directory, other file types.
* Archive extended attributes, ACLs, other metadata.
@@ -243,6 +261,19 @@ DEFINE_TEST(test_write_format_pax)
assertEqualIntA(a, 8, archive_read_data(a, buff2, 10));
assertEqualMem(buff2, "12345678", 8);
/*
* Read the all-slash pathname entry.
*/
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualString(long_slashes, archive_entry_pathname(ae));
assertEqualInt(2, archive_entry_atime(ae));
assertEqualInt(20, archive_entry_atime_nsec(ae));
assertEqualInt(4, archive_entry_ctime(ae));
assertEqualInt(40, archive_entry_ctime_nsec(ae));
assertEqualInt(5, archive_entry_mtime(ae));
assertEqualInt(50, archive_entry_mtime_nsec(ae));
assertEqualInt(0, archive_entry_size(ae));
/*
* Verify the end of the archive.
*/