From: Zhaofeng Li Date: Sat, 24 May 2025 19:45:18 +0000 (-0600) Subject: tar: Reset accumulated header state after reading macOS metadata blob X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5bb36db5e19aecabccec8f351ec22f8c3a8695f0;p=thirdparty%2Flibarchive.git tar: Reset accumulated header state after reading macOS metadata blob AppleDouble extension entries are present as separate files immediately preceding the corresponding real files. In libarchive, we process the entire metadata file (headers + data) as if it were a header in the real file. However, the code forgets to reset the accumulated header state before parsing the real file's headers. In one code path, this causes the metadata file's name to be used as the real file's name. Specifically, this can be triggered with a tar containing two files: 1. A file named `._badname` with pax header containing the `path` attribute 2. A file named `goodname` _with_ a pax header but _without_ the `path` attribute libarchive will list one file, `._badname` containing the data of `goodname`. This code is pretty brittle and we really should let the client deal with it :( Fixes #2510. Signed-off-by: Zhaofeng Li --- diff --git a/libarchive/archive_read_support_format_tar.c b/libarchive/archive_read_support_format_tar.c index e9b3312a2..4ead50c7d 100644 --- a/libarchive/archive_read_support_format_tar.c +++ b/libarchive/archive_read_support_format_tar.c @@ -701,6 +701,22 @@ archive_read_format_tar_skip(struct archive_read *a) return (ARCHIVE_OK); } +/* + * This function resets the accumulated state while reading + * a header. + */ +static void +tar_reset_header_state(struct tar *tar) +{ + tar->pax_hdrcharset_utf8 = 1; + tar->sparse_gnu_attributes_seen = 0; + archive_string_empty(&(tar->entry_gname)); + archive_string_empty(&(tar->entry_pathname)); + archive_string_empty(&(tar->entry_pathname_override)); + archive_string_empty(&(tar->entry_uname)); + archive_string_empty(&tar->entry_linkpath); +} + /* * This function reads and interprets all of the headers associated * with a single entry. @@ -726,13 +742,7 @@ tar_read_header(struct archive_read *a, struct tar *tar, static const int32_t seen_x_header = 32; /* Also X */ static const int32_t seen_mac_metadata = 512; - tar->pax_hdrcharset_utf8 = 1; - tar->sparse_gnu_attributes_seen = 0; - archive_string_empty(&(tar->entry_gname)); - archive_string_empty(&(tar->entry_pathname)); - archive_string_empty(&(tar->entry_pathname_override)); - archive_string_empty(&(tar->entry_uname)); - archive_string_empty(&tar->entry_linkpath); + tar_reset_header_state(tar); /* Ensure format is set. */ if (a->archive.archive_format_name == NULL) { @@ -936,6 +946,7 @@ tar_read_header(struct archive_read *a, struct tar *tar, err = err_combine(err, err2); /* Note: Other headers can appear again. */ seen_headers = seen_mac_metadata; + tar_reset_header_state(tar); break; }