]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
7zip writer: free file->utf16name on symlink UTF-8 conversion failure 3062/head
authorSanjayR <sanjayr@ymail.com>
Fri, 22 May 2026 05:36:50 +0000 (11:06 +0530)
committerSanjayR <sanjayr@ymail.com>
Fri, 22 May 2026 05:36:50 +0000 (11:06 +0530)
  file_new() at archive_write_set_format_7zip.c:1688 calls free(file)
  on the symlink-UTF8-failure branch, leaving file->utf16name
  (allocated at line 1666) leaked. The two earlier free(file) calls
  in this function (lines 1656, 1668) are correct because they happen
  BEFORE utf16name is allocated, but the third one happens after.

  The rest of the function uses file_free() on every other
  post-utf16name error path; file_free() does free(file->utf16name)
  followed by free(file), which is the cleanup convention. Replacing
  free(file) with file_free(file) makes the symlink-error branch
  consistent with everything else.

  Reproduces with bsdtar in a non-UTF-8 locale with a non-UTF-8
  symlink target:
      ln -s "$(printf 'broken_\\xff\\xfe_link')" sym
      LC_ALL=C ASAN_OPTIONS=detect_leaks=1 \
        bsdtar --format=7zip -cf out.7z sym
  => LeakSanitizer: 30-48 byte direct leak; allocation site is
     file_new (archive_write_set_format_7zip.c:1666).

  Equivalent trigger: any libarchive caller that sets AE_IFLNK
  filetype on an entry without ever calling
  archive_entry_set_symlink() (then archive_entry_symlink_utf8()
  returns NULL and the error branch fires).

  Code unchanged since the 7zip writer's introduction; no existing
  test exercises this error path.

  Identified by Neurolog, a code-analysis tool the reporter is
  developing that combines Souffle Datalog with LLM-assisted fact
  extraction. The reproducer was separately validated under LeakSanitizer
  against current master.

libarchive/archive_write_set_format_7zip.c

index 1bbd24d632e7877465904d9fca7d5e705d87d49f..a0dcc537641ee1b7ed91870fac9070e42475d6bd 100644 (file)
@@ -1685,7 +1685,7 @@ file_new(struct archive_write *a, struct archive_entry *entry,
                const char* linkpath;
                linkpath = archive_entry_symlink_utf8(entry);
                if (linkpath == NULL) {
-                       free(file);
+                       file_free(file);
                        archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
                            "symlink path could not be converted to UTF-8");
                        return (ARCHIVE_FAILED);