[Bug 8741] New: Any throw statement causes memory corruption

bugzilla at busybox.net bugzilla at busybox.net
Thu Mar 3 20:32:43 UTC 2016


            Bug ID: 8741
           Summary: Any throw statement causes memory corruption
           Product: uClibc++
           Version: 0.2.5
          Hardware: All
                OS: All
            Status: NEW
          Severity: critical
          Priority: P5
         Component: Standard Compliance
          Assignee: unassigned at uclibc.org
          Reporter: pixus.ru at gmail.com
                CC: uclibc-cvs at uclibc.org
  Target Milestone: ---

I have discovered that uClibc++ incorrectly implements C++ exception ABI,
allocating not enough memory in the "__cxxabiv1::__cxa_allocate_exception":

/// code begin ///
retval = malloc (thrown_size + sizeof(__cxa_exception));
/// code end ///

uClibc++ allocates "thrown_size + sizeof(__cxa_exception)" while stdlibc++
allocates "thrown_size += sizeof (__cxa_refcounted_exception);" since
2009-01-07 (https://gcc.gnu.org/bugzilla/attachment.cgi?id=17047) .

The "__cxa_refcounted_exception" is wrapper around "__cxa_exception" and thus
bigger than "__cxa_exception" alone.
That causes memory corruption (buffer overflow) inside
"__cxxabiv1::__cxa_throw" which is not implemented by uClibc++, but implemented
by GCC's libsupc++:

/// code begin (gcc-5.2.0/libstdc++-v3/libsupc++/eh_throw.cc:69) ///
__cxa_refcounted_exception *header
  = __get_refcounted_exception_header_from_obj (obj);
header->referenceCount = 1;
/// code end ///

In the code above, the "header->referenceCount = 1" writes in memory preceding
region allocated for both thrown exception object and exception's structure.
The "obj" is pointer to memory allocated by
"__cxxabiv1::__cxa_allocate_exception", the
"__get_refcounted_exception_header_from_obj (obj)" is defined as:

/// code begin ///
static inline __cxa_refcounted_exception *
__get_refcounted_exception_header_from_obj (void *ptr)
  return reinterpret_cast<__cxa_refcounted_exception *>(ptr) - 1;
/// code end ///

Thus GCC's libsupc++ expects enough memory allocated preceding exception object
to keep structure "__cxa_refcounted_exception", but uClibc++ allocates only
"sizeof(__cxa_exception)" bytes before exception object.

When binary is compiled for OpenWRT's musl libc standard library, the program
crashes with SIGSEGV in the "free" call from "__cxxabiv1::__cxa_free_exception"
because musl is very sensitive for memory corruption (musl's malloc stores
meta-information about memory region in 8 bytes right before memory chunk
When compiled against glibc, the segmentation fault does not happen immediately
in the "__cxxabiv1::__cxa_free_exception", but memory corruption still should
take place, yielding undefined behavior.

For your convenience, I have created OpenWRT package and feed for this test
package: https://github.com/CoolSpot/openwrt-test/throw-catch-sigsegv
feed: https://github.com/CoolSpot/openwrt-test-packages

### Installing the feed
cd ~/Documents/openwrt
echo "src-git openwrttest
https://github.com/coolspot/openwrt-test-packages.git" >> ./feeds.conf
./scripts/feeds update openwrttest
./scripts/feeds install -a -p openwrttest

### Building the package
make menuconfig
# In the menuconfig select the package Test/sub-test/throw-catch-sigsegv to be
make package/throw-catch-sigsegv/install
# Copy the package on the device (or VM)
# on the device (or VM)
root at OpenWrt:~# opkg install /tmp/throw-catch-sigsegv_2016-02-25_malta_mips.ipk

I am using following setup for reproducing:
OpenWRT commit 4885087731e4ee9ac9823bd5cf3e777eecfd33d9 (Tue Feb 23 14:40:40
2016 +0000)

I will provide proposed patch soon.

You are receiving this mail because:
You are on the CC list for the bug.

More information about the uClibc-cvs mailing list