Project

General

Profile

Actions

Bug #4495

open

Strange buffer overflow / random crash of chronosync::Socket related to ndn::InMemoryStorage

Added by Alex Afanasyev about 6 years ago. Updated about 6 years ago.

Status:
New
Priority:
Normal
Assignee:
-
Start date:
02/08/2018
Due date:
% Done:

0%

Estimated time:

Description

The following snippet suppose to work without problems

test.cpp:

#include <iostream>
#include <sstream>
#include <unordered_map>
#include <memory>

#include <ndn-cxx/face.hpp>
#include <ndn-cxx/name.hpp>
#include <ndn-cxx/security/key-chain.hpp>

#include <ChronoSync/socket.hpp>

#include <boost/asio.hpp>

int
main()
{
  using namespace ndn;

  KeyChain keychain;
  boost::asio::io_service io;
  Face face(nullptr, io, keychain);

  auto socket3 = std::make_shared<chronosync::Socket>("/test/sync2", "/test/user2",
                            face,
                            [] (const std::vector<chronosync::MissingDataInfo>& info) {
                              std::cerr << "Update" << std::endl;
                            },
                            Name("/hello"),
                            nullptr,
                            ndn::time::seconds(60));

  face.processEvents();
}

g++ -std=c++11 `pkg-config --cflags libndn-cxx` `pkg-config --cflags ChronoSync` test.cpp `pkg-config --libs libndn-cxx` `pkg-config --libs ChronoSync` -fsanitize=address

However, when ndn-cxx compiled --with-sanitizer=address, it results in a stable crash

./a.out
==13619==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x620000001fe0 at pc 0x00011143d118 bp 0x7ffee0077310 sp 0x7ffee0076ac0
WRITE of size 64 at 0x620000001fe0 thread T0
    #0 0x11143d117 in __asan_memset (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x51117)
    #1 0x10fcfa7f1 in ndn::InMemoryStorage::InMemoryStorage(unsigned long) deque:1094
    #2 0x10fcfa104 in ndn::InMemoryStoragePersistent::InMemoryStoragePersistent() in-memory-storage-persistent.cpp:27
    #3 0x11129a72c in chronosync::Socket::Socket(ndn::Name const&, ndn::Name const&, ndn::Face&, std::__1::function<void (std::__1::vector<chronosync::MissingDataInfo, std::__1::allocator<chronosync::MissingDataInfo> > const&)> const&, ndn::Name const&, std::__1::shared_ptr<ndn::security::v2::Validator>, boost::chrono::duration<long long, boost::ratio<1l, 1000l> > const&) socket.cpp:36
    #4 0x10fb9a9f7 in std::__1::shared_ptr<chronosync::Socket> std::__1::shared_ptr<chronosync::Socket>::make_shared<char const (&) [12], char const (&) [12], ndn::Face&, main::$_0, ndn::Name, std::nullptr_t, boost::chrono::duration<long long, boost::ratio<1l, 1l> > >(char const (&&&) [12], char const (&&&) [12], ndn::Face&&&, main::$_0&&, ndn::Name&&, std::nullptr_t&&, boost::chrono::duration<long long, boost::ratio<1l, 1l> >&&) (ndn-proxy:x86_64+0x1000159f7)
    #5 0x10fb8c57a in main (ndn-proxy:x86_64+0x10000757a)
    #6 0x7fff59c6f114 in start (libdyld.dylib:x86_64+0x1114)

0x620000001fe0 is located 0 bytes to the right of 3936-byte region [0x620000001080,0x620000001fe0)
allocated by thread T0 here:
    #0 0x1114500ab in wrap__Znwm (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x640ab)
    #1 0x10fb98d1f in std::__1::shared_ptr<chronosync::Socket> std::__1::shared_ptr<chronosync::Socket>::make_shared<char const (&) [12], char const (&) [12], ndn::Face&, main::$_0, ndn::Name, std::nullptr_t, boost::chrono::duration<long long, boost::ratio<1l, 1l> > >(char const (&&&) [12], char const (&&&) [12], ndn::Face&&&, main::$_0&&, ndn::Name&&, std::nullptr_t&&, boost::chrono::duration<long long, boost::ratio<1l, 1l> >&&) (ndn-proxy:x86_64+0x100013d1f)
    #2 0x10fb8c57a in main (ndn-proxy:x86_64+0x10000757a)
    #3 0x7fff59c6f114 in start (libdyld.dylib:x86_64+0x1114)

SUMMARY: AddressSanitizer: heap-buffer-overflow (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x51117) in __asan_memset
Shadow bytes around the buggy address:
  0x1c40000003a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1c40000003b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1c40000003c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1c40000003d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x1c40000003e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x1c40000003f0: 00 00 00 00 00 00 00 00 00 00 00 00[fa]fa fa fa
  0x1c4000000400: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c4000000410: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c4000000420: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c4000000430: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c4000000440: 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
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  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
==13619==ABORTING
Abort trap: 6

Changing std::deque to std::list/vector, resolves the problem, but I'm really puzzled of what is going on.


Files

4495.travis.yml (1.29 KB) 4495.travis.yml .travis.yml to reproduce the bug Junxiao Shi, 02/11/2018 08:52 AM
4495-valgrind.travis.yml (1.22 KB) 4495-valgrind.travis.yml .travis.yml to reproduce the bug with valgrind instead of ASan Junxiao Shi, 02/11/2018 09:46 AM
Actions #1

Updated by Davide Pesavento about 6 years ago

I cannot reproduce the AddressSanitizer error on Linux using the test program in the description.

Actions #2

Updated by Alex Afanasyev about 6 years ago

Which specific Linux? I have stably reproduced it on macOS 10.13.3 with clang 9.0.0 (clang-900.0.39.2) and on Ubuntu 16.04 with default gcc5.

Actions #3

Updated by Davide Pesavento about 6 years ago

Ubuntu 17.10 x86_64 with standard gcc compiler and standard everything else.

Actions #4

Updated by Alex Afanasyev about 6 years ago

  • Description updated (diff)
Actions #5

Updated by Alex Afanasyev about 6 years ago

  • Description updated (diff)
Actions #6

Updated by Alex Afanasyev about 6 years ago

  • Description updated (diff)
Actions #7

Updated by Alex Afanasyev about 6 years ago

  • Description updated (diff)
Actions #8

Updated by Alex Afanasyev about 6 years ago

  • Description updated (diff)
Actions #9

Updated by Alex Afanasyev about 6 years ago

Repeated the same issue on 14.04 and 17.10.

One things that I didn't specify originally, ndn-cxx, ChronoSync, and NFD are compiled with debug symbols (./waf configure --debug --with-sanitizer=address). You also need to run NFD before running the snippet.

Actions #10

Updated by Davide Pesavento about 6 years ago

Alex Afanasyev wrote:

Repeated the same issue on 14.04 and 17.10.

One things that I didn't specify originally, ndn-cxx, ChronoSync, and NFD are compiled with debug symbols (./waf configure --debug --with-sanitizer=address). You also need to run NFD before running the snippet.

Yes, I was using --debug as well.

However, when ndn-cxx compiled --with-sanitizer=address, it results in a stable crash

So you're building only ndn-cxx with ASan, not ChronoSync..?

Actions #11

Updated by Alex Afanasyev about 6 years ago

So you're building only ndn-cxx with ASan, not ChronoSync..?

No. Everything was with --debug and --with-sanitizer=address. On all systems I tested (14.04, 16.04, 17.10, macOS 10.13) it crashed with a buffer overflow report.

Actions #12

Updated by Junxiao Shi about 6 years ago

I'm able to reproduce this bug on Ubuntu 14.04.

https://travis-ci.org/yoursunny/TravisCI-temp/builds/340164777

Actions #14

Updated by Alex Afanasyev about 6 years ago

Davide discovered a changeable ABI when compiled with _DEBUG define. When compiling the snippet using -D_DEBUG=1, it no longer crashes.

g++ -D_DEBUG=1 -std=c++11 `pkg-config --cflags libndn-cxx` `pkg-config --cflags ChronoSync` test.cpp `pkg-config --libs libndn-cxx` `pkg-config --libs ChronoSync` -fsanitize=address

Will try to investigate whether it fixes my actual problem.

Actions #15

Updated by Davide Pesavento about 6 years ago

Alex Afanasyev wrote:

Davide discovered a changeable ABI when compiled with _DEBUG define.

Specifically, class chronosync::Logic changes size depending on _DEBUG:

class Logic : noncopyable
{
  ...
private:
  ... // many other members

#ifdef _DEBUG
  int m_instanceId;
  static int s_instanceCounter;
#endif
};

Logic is a member of Socket, thus Socket changes size too. If a translation unit is compiled without -D_DEBUG, it will not allocate enough memory for an instance of Socket that was compiled in debug mode. Eventually, the last member of the structure (which happens to be the unique_ptr<Scheduler> in InMemoryStoragePersistent) will overflow the allocated area when initialized.

Actions #16

Updated by Junxiao Shi about 6 years ago

  • Project changed from ndn-cxx to ChronoSync
  • Category deleted (Utils)
  • Target version deleted (v0.7)

The lesson: don’t use preprocessor conditionals to add or remove fields in headers unless the defines are in a common header from the same project and cannot be overridden from outside the project.

Actions #17

Updated by Alex Afanasyev about 6 years ago

We should tell that Crytpo++ and Boot.Log developers who are quite abusing this :)

Actions

Also available in: Atom PDF