]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
warc writer: free hdr on _popul_ehdr overflow in _warc_header 3061/head
authorSanjayR <sanjayr@ymail.com>
Fri, 22 May 2026 05:03:56 +0000 (10:33 +0530)
committerSanjayR <sanjayr@ymail.com>
Mon, 25 May 2026 06:07:20 +0000 (11:37 +0530)
  _warc_header() initialises a local archive_string hdr, fills it via
  _popul_ehdr(), and frees it on the success path at the bottom. The
  intermediate error return on r < 0 (the populated header exceeds
  MAX_HDR_SIZE=512, reachable with a long enough pathname carried by
  WARC-Target-URI) returns ARCHIVE_WARN without freeing hdr.

  By the time _popul_ehdr returns -1 hdr already holds the WARC version
  line, WARC-Type, WARC-Target-URI (long path), WARC-Date, Last-Modified,
  WARC-Record-ID, and Content-Length headers --- ~1 KB+ per entry in
  practice.

  Reproduces with the bundled bsdtar against a regular file with a
  ~400+ char pathname:
      ASAN_OPTIONS=detect_leaks=1 bsdtar --format=warc -cf out.warc <long_path>
  => LeakSanitizer: ~1 KB direct leak; stack pierces _popul_ehdr ->
     _warc_header (archive_write_set_format_warc.c:245) ->
     _archive_write_header -> ... -> main.

  Code unchanged since the file's introduction in 2014; no existing test
  exercises the long-pathname path. The warcinfo branch above (line ~217)
  handles this correctly already (frees hdr unconditionally outside the
  "if (r >= 0)" block); only the WT_RSRC branch was missed.

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

libarchive/archive_write_set_format_warc.c

index 5a0ca0b5261108c008bd2f11caa1912169bec292..2192995362a538f8c2868eb9481b6a5052babe31 100644 (file)
@@ -245,6 +245,7 @@ _warc_header(struct archive_write *a, struct archive_entry *entry)
                r = _popul_ehdr(&hdr, MAX_HDR_SIZE, rh);
                if (r < 0) {
                        /* don't bother */
+                       archive_string_free(&hdr);
                        archive_set_error(
                                &a->archive,
                                ARCHIVE_ERRNO_FILE_FORMAT,