Project: libarchive (libarchive/libarchive), language: c++
Vulnerability instance: libarchive.cve-2016-10209
Sanitizer: address

================= Bug Report (1/1) ==================
## Source: GitHub Issue
## URL: https://github.com/libarchive/libarchive/issues/842
## Description:
Issue: libarchive/libarchive#842
Title: SIGSEGV in archive_wstring_append_from_mbs()
State: closed
Created by: fumfel
Created at: 2016-12-12 17:47:50+00:00

Issue Body:
**SIGSEGV in archive_wstring_append_from_mbs()**

Tested on Git HEAD: 54546be8a7a2e69738247d68f4f6c253430a3d6f

Payload: https://frankowicz.me/storage/crashes/la_segv_archive_wstring_append_from_mbs

To reproduce: `bsdtar -t -f la_segv_archive_wstring_append_from_mbs`

ASAN Output:
```
==1002==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x0000005fb3cc bp 0x7ffc5999dae0 sp 0x7ffc5999daa0 T0)
    #0 0x5fb3cb in archive_wstring_append_from_mbs libarchive/archive_string.c:603
    #1 0x60363a in archive_mstring_get_wcs libarchive/archive_string.c:3929
    #2 0x42a1c4 in archive_entry_pathname_w libarchive/archive_entry.c:580
    #3 0x5bfee9 in zip_read_local_file_header libarchive/archive_read_support_format_zip.c:871
    #4 0x5c2b1d in archive_read_format_zip_streamable_read_header libarchive/archive_read_support_format_zip.c:2149
    #5 0x45841b in _archive_read_next_header2 libarchive/archive_read.c:648
    #6 0x45841b in _archive_read_next_header libarchive/archive_read.c:686
    #7 0x41280f in read_archive tar/read.c:261
    #8 0x414b06 in tar_mode_t tar/read.c:94
    #9 0x40963f in main tar/bsdtar.c:803
    #10 0x7fb92a6f482f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #11 0x40c3e8 in _start (/usr/local/bin/bsdtar+0x40c3e8)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV libarchive/archive_string.c:603 
```archive_wstring_append_from_mbs
==1002==ABORTING




Comments:
Comment by mmatuska on 2016-12-29 19:48:53+00:00:
Could you please re-test with latest master?

---

Comment by fumfel on 2016-12-29 23:42:51+00:00:
e8a9de5eaf3b79fc3d990d056343bb52c51c5ba4 works fine :)

---

Comment by rhertzog on 2017-04-06 16:14:53+00:00:
@fumfel I am unable to reproduce the segfault, not even when I reuse the very same git commit as you. Is https://frankowicz.me/storage/crashes/la_segv_archive_wstring_append_from_mbs the correct payload ?

Here's the checksum of the file that I downloaded:
$ sha1sum CVE-2016-10209-la_segv_archive_wstring_append_from_mbs 
594afbd22628a6f78b466d235e235eebd25fb029  CVE-2016-10209-la_segv_archive_wstring_append_from_mbs

Instead of the segfault I always get this error message:
$ bsdtar -t -f CVE-2016-10209-la_segv_archive_wstring_append_from_mbs 
bsdtar: Archive entry has empty or unreadable filename ... skipping.
bsdtar: (null)
bsdtar: Error exit delayed from previous errors.


---

Comment by carnil on 2017-04-07 04:48:22+00:00:
Looking at the possible commits which fix the issue I guess the right one is 42a3408ac7df1e69bea9ea12b72e14f59f7400c0 (as e8a9de5 is just a change for the "Fix style typo in tar.5"), which is as well between the reporting date and the confirm that it does not happen anymore on "latest master".

---

Comment by carnil on 2017-04-07 04:49:38+00:00:
FTR, this issue has been assigned [CVE-2016-10209](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-10209)

---

Comment by attritionorg on 2017-04-08 16:45:19+00:00:
For reference, this is also known as CVE-2016-1000349 which is listed as an assignment duplicate.

---

Comment by msmeissn on 2017-04-10 14:18:56+00:00:
are you using a special $LANG   ?

---

Comment by rhertzog on 2017-04-10 14:27:19+00:00:
@msmeissn I have LANG set but it's not really a "special" value, just plain French.

```
$ env|grep LANG
LANG=fr_FR.UTF-8
GDM_LANG=fr_FR.UTF-8```


---

Comment by msmeissn on 2017-04-10 14:29:11+00:00:
i was wondering about the original reporter. I also cannot get it crash with "C" or de_DE.utf8

---

Comment by fumfel on 2017-04-10 15:55:59+00:00:
I don't remember - probably I have "pl_PL.utf8" or "en_US.utf8".

Commit References:
e8a9de5eaf3b79fc3d990d056343bb52c51c5ba4
594afbd22628a6f78b466d235e235eebd25fb029
42a3408ac7df1e69bea9ea12b72e14f59f7400c0
54546be8a7a2e69738247d68f4f6c253430a3d6f

Build script:
#!/bin/bash -eu
# Minimized build script with only core build commands
set -eu
./configure
make -j$(nproc) all

Dockerfile:
FROM hwiwonlee/secb.base:latest
RUN apt-get install -y make autoconf automake libtool pkg-config libbz2-dev liblzo2-dev liblzma-dev liblz4-dev libz-dev libxml2-dev libssl-dev
RUN git clone https://github.com/libarchive/libarchive libarchive
RUN git -C libarchive checkout 629358182b04d7de2316bbd29708c58ddf797fd2
WORKDIR $SRC/libarchive
COPY build.sh $SRC/

Additional files:
filename: libarchive_fuzzer.cc
content: // Copyright 2016 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
#include <stddef.h>
#include <stdint.h>
#include <vector>

#include "archive.h"

struct Buffer {
  const uint8_t *buf;
  size_t len;
};

ssize_t reader_callback(struct archive *a, void *client_data,
                        const void **block) {
  Buffer *buffer = reinterpret_cast<Buffer *>(client_data);
  *block = buffer->buf;
  ssize_t len = buffer->len;
  buffer->len = 0;
  return len;
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
  struct archive *a = archive_read_new();

  archive_read_support_filter_all(a);
  archive_read_support_format_all(a);

  Buffer buffer = {buf, len};
  archive_read_open(a, &buffer, NULL, reader_callback, NULL);

  std::vector<uint8_t> data_buffer(getpagesize(), 0);
  struct archive_entry *entry;
  while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
    while (archive_read_data(a, data_buffer.data(), data_buffer.size()) > 0)
      ;
  }

  archive_read_free(a);
  return 0;
}

filename: target.yaml
content: homepage: "https://github.com/libarchive/libarchive"