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

================= Bug Report (1/1) ==================
## Source: GitHub Issue
## URL: https://github.com/libarchive/libarchive/issues/835
## Description:
Issue: libarchive/libarchive#835
Title: heap-buffer-overflow in archive_read_format_cab_read_header
State: closed
Created by: asarubbo
Created at: 2016-12-06 11:07:26+00:00

Issue Body:
On 3.2.2:

```
# bsdtar -t -f $FILE
=================================================================                                                                                                                              
==21129==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61500000ff00 at pc 0x7fa070bd7827 bp 0x7fffb7183a30 sp 0x7fffb7183a28                                                      
READ of size 1 at 0x61500000ff00 thread T0                                                                                                                                                     
    #0 0x7fa070bd7826 in archive_read_format_cab_read_header /tmp/portage/app-arch/libarchive-3.2.2/work/libarchive-3.2.2/libarchive/archive_read_support_format_cab.c:903:9                   
    #1 0x7fa070b7145b in _archive_read_next_header2 /tmp/portage/app-arch/libarchive-3.2.2/work/libarchive-3.2.2/libarchive/archive_read.c:649:7                                               
    #2 0x7fa070b71100 in _archive_read_next_header /tmp/portage/app-arch/libarchive-3.2.2/work/libarchive-3.2.2/libarchive/archive_read.c:687:8                                                
    #3 0x514c89 in read_archive /tmp/portage/app-arch/libarchive-3.2.2/work/libarchive-3.2.2/tar/read.c:261:7                                                                                  
    #4 0x51416b in tar_mode_t /tmp/portage/app-arch/libarchive-3.2.2/work/libarchive-3.2.2/tar/read.c:94:2                                                                                     
    #5 0x50f1a8 in main /tmp/portage/app-arch/libarchive-3.2.2/work/libarchive-3.2.2/tar/bsdtar.c:803:3
    #6 0x7fa06fc0461f in __libc_start_main /var/tmp/portage/sys-libs/glibc-2.22-r4/work/glibc-2.22/csu/libc-start.c:289
    #7 0x41c168 in _init (/usr/bin/bsdtar+0x41c168)

0x61500000ff00 is located 0 bytes to the right of 512-byte region [0x61500000fd00,0x61500000ff00)
allocated by thread T0 here:
    #0 0x4d4f28 in malloc /tmp/portage/sys-devel/llvm-3.9.0-r1/work/llvm-3.9.0.src/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:64
    #1 0x7fa070b6c854 in __archive_read_filter_ahead /tmp/portage/app-arch/libarchive-3.2.2/work/libarchive-3.2.2/libarchive/archive_read.c:1436:17
    #2 0x7fa070c528cd in archive_read_format_tar_bid /tmp/portage/app-arch/libarchive-3.2.2/work/libarchive-3.2.2/libarchive/archive_read_support_format_tar.c:310:6
    #3 0x7fa070b66670 in choose_format /tmp/portage/app-arch/libarchive-3.2.2/work/libarchive-3.2.2/libarchive/archive_read.c:712:10
    #4 0x7fa070b66670 in archive_read_open1 /tmp/portage/app-arch/libarchive-3.2.2/work/libarchive-3.2.2/libarchive/archive_read.c:529
    #5 0x7fa070b8d2e1 in archive_read_open_filenames /tmp/portage/app-arch/libarchive-3.2.2/work/libarchive-3.2.2/libarchive/archive_read_open_filename.c:152:10
    #6 0x7fa070b8ce8b in archive_read_open_filename /tmp/portage/app-arch/libarchive-3.2.2/work/libarchive-3.2.2/libarchive/archive_read_open_filename.c:109:9
    #7 0x5149eb in read_archive /tmp/portage/app-arch/libarchive-3.2.2/work/libarchive-3.2.2/tar/read.c:223:6
    #8 0x51416b in tar_mode_t /tmp/portage/app-arch/libarchive-3.2.2/work/libarchive-3.2.2/tar/read.c:94:2
    #9 0x50f1a8 in main /tmp/portage/app-arch/libarchive-3.2.2/work/libarchive-3.2.2/tar/bsdtar.c:803:3
    #10 0x7fa06fc0461f in __libc_start_main /var/tmp/portage/sys-libs/glibc-2.22-r4/work/glibc-2.22/csu/libc-start.c:289

SUMMARY: AddressSanitizer: heap-buffer-overflow /tmp/portage/app-arch/libarchive-3.2.2/work/libarchive-3.2.2/libarchive/archive_read_support_format_cab.c:903:9 in archive_read_format_cab_read_header
Shadow bytes around the buggy address:
  0x0c2a7fff9f90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c2a7fff9fa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c2a7fff9fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c2a7fff9fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c2a7fff9fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c2a7fff9fe0:[fa]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c2a7fff9ff0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c2a7fffa000: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c2a7fffa010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c2a7fffa020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c2a7fffa030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==21129==ABORTING
```

Testcase: https://github.com/asarubbo/poc/blob/master/00106-libarchive-heapoverflow-archive_read_format_cab_read_header

Could you check if it a duplicate of #797 or a similar bug?


Comments:
Comment by jsonn on 2016-12-06 16:36:25+00:00:
Please test against trunk.

---

Comment by asarubbo on 2016-12-06 17:51:57+00:00:
current master seems to be fine with the provided testcase

---

Comment by carnil on 2017-05-01 12:25:15+00:00:
This issue has been assigned [CVE-2016-10350](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-10350)

---

Comment by carnil on 2017-05-01 13:09:03+00:00:
Hi

I tried to bisect to find the fixing commit, the following lead me to 88eb9e1d73fef46f04677c25b1697b8e25777ed3 to fix this issue.

```
git bisect start '--term-old' 'broken' '--term-new' 'fixed'
# broken: [629358182b04d7de2316bbd29708c58ddf797fd2] Libarchive 3.2.2
git bisect broken 629358182b04d7de2316bbd29708c58ddf797fd2
# fixed: [b68a5cd06c38281ff24af7e7ab79a5118018c085] Fix build on ancient systems without int64_t definition.
git bisect fixed b68a5cd06c38281ff24af7e7ab79a5118018c085
# fixed: [6a509898d71ad4b31e4e4a00f42f7e8b00b7f03a] Disable automatic detection of liblzo2 Replace liblzo with lzop in Travis CI builds Fix lzop tests
git bisect fixed 6a509898d71ad4b31e4e4a00f42f7e8b00b7f03a
# fixed: [7f6565656cf20c74057289d784f548ffd189b416] Allocate memory precisely. Avoid recomputions of sizes.
git bisect fixed 7f6565656cf20c74057289d784f548ffd189b416
# fixed: [ddb3954bfdb9a0a98d50fb1c50cbecb603d9adf0] Add more explanation comments to validate_number_field()
git bisect fixed ddb3954bfdb9a0a98d50fb1c50cbecb603d9adf0
# broken: [515c0f32612d990af5e4245dcdb135a89432a9ed] Merge pull request #825 from josusky/master
git bisect broken 515c0f32612d990af5e4245dcdb135a89432a9ed
# broken: [fa8dc4e93c45182de73cded86ebf58a348851f05] Spelling fixes (#830)
git bisect broken fa8dc4e93c45182de73cded86ebf58a348851f05
# fixed: [53d73345410d69e68171f05facaf4523e38e72bb] Fix heap buffer overflow in uudecode_bidder_bid()
git bisect fixed 53d73345410d69e68171f05facaf4523e38e72bb
# fixed: [88eb9e1d73fef46f04677c25b1697b8e25777ed3] Reread the CAB header skipping the self-extracting binary code.
git bisect fixed 88eb9e1d73fef46f04677c25b1697b8e25777ed3
# broken: [2d2b3e928605f795515b03f060fd638c265b0778] Restore compatibility with Perl Archive::Tar that was broken with #825
git bisect broken 2d2b3e928605f795515b03f060fd638c265b0778
# first fixed commit: [88eb9e1d73fef46f04677c25b1697b8e25777ed3] Reread the CAB header skipping the self-extracting binary code
```

Commit References:
7f6565656cf20c74057289d784f548ffd189b416
2d2b3e928605f795515b03f060fd638c265b0778
fa8dc4e93c45182de73cded86ebf58a348851f05
515c0f32612d990af5e4245dcdb135a89432a9ed
629358182b04d7de2316bbd29708c58ddf797fd2
6a509898d71ad4b31e4e4a00f42f7e8b00b7f03a
ddb3954bfdb9a0a98d50fb1c50cbecb603d9adf0
88eb9e1d73fef46f04677c25b1697b8e25777ed3
b68a5cd06c38281ff24af7e7ab79a5118018c085
53d73345410d69e68171f05facaf4523e38e72bb

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"