From patchwork Fri Mar 4 19:48:03 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ivan Koldaev X-Patchwork-Id: 592196 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by ozlabs.org (Postfix) with ESMTP id 53ED51401C7 for ; Sat, 5 Mar 2016 06:54:13 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="key not found in DNS" (0-bit key; unprotected) header.d=pixus.ru header.i=@pixus.ru header.b=ERDBsJZJ; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=nVFD6JK0; dkim-atps=neutral Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id CB87A92494; Fri, 4 Mar 2016 19:54:12 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id SXzMOTO2GGdT; Fri, 4 Mar 2016 19:54:11 +0000 (UTC) Received: from ash.osuosl.org (ash.osuosl.org [140.211.166.34]) by whitealder.osuosl.org (Postfix) with ESMTP id D5C7C92296; Fri, 4 Mar 2016 19:54:10 +0000 (UTC) X-Original-To: uclibc@lists.busybox.net Delivered-To: uclibc@osuosl.org Received: from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138]) by ash.osuosl.org (Postfix) with ESMTP id 318C61C0975 for ; Fri, 4 Mar 2016 19:54:10 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by whitealder.osuosl.org (Postfix) with ESMTP id 29BF792296 for ; Fri, 4 Mar 2016 19:54:10 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from whitealder.osuosl.org ([127.0.0.1]) by localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id GrSih1deZ0bY for ; Fri, 4 Mar 2016 19:54:08 +0000 (UTC) X-Greylist: delayed 00:06:03 by SQLgrey-1.7.6 Received: from mail-ob0-f176.google.com (mail-ob0-f176.google.com [209.85.214.176]) by whitealder.osuosl.org (Postfix) with ESMTPS id 9E344921AF for ; Fri, 4 Mar 2016 19:54:08 +0000 (UTC) Received: by mail-ob0-f176.google.com with SMTP id rt7so59294182obb.3 for ; Fri, 04 Mar 2016 11:54:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pixus.ru; s=google; h=mime-version:sender:date:message-id:subject:from:to; bh=Kgsf1eMaam/R8Vw8rdpi37LBHaVJvCxqS+i6Q+4F+h8=; b=ERDBsJZJVfcdCiDHV+iBae8YupEmNOOuvazOMNde/2BaBo77rndxA3PKd2J0Yv0HoN TA2Zpad9kVYV7Wp+gIPSwlM8kXdWpYARxrW3WBXYKd2Y3kDc+QXw3yBD2fPmzcjn2q6h hTPyGzRI8qRHiMOHo6R+xVvetVzfsh5m+9yuM= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:sender:date:message-id:subject:from:to; bh=Kgsf1eMaam/R8Vw8rdpi37LBHaVJvCxqS+i6Q+4F+h8=; b=nVFD6JK0CHO80onlP0K8di0sJjLBiMhUlosqMQiymTyM5az6tniLMQUL9QZ7iSZcrm +KU/0XhVYpK7vwPoP5OEqr3B9vbAv7JjvSWHQy8VlNfvaFNuTiL1h4G+hsmPXH1WXhvH 2utMJDY6f/YLvu9JOBqkPtnq51HVM6sJiBRKYyz1CZVWyQhz/9fjwmMMzwGoRcDKjWhQ VdLUvLCEEMXSz1o3BWhqy0C2s6mf3J/QEePaMcVgI2CE5uSy7uSTrf+bDEDmd5EwWuVq zYbXY1Pe4xfOvzli+209aDPLJqMAQwY125a+68XR6x9xT5Mggg1JjspzI6mQ+4aLsjOZ xHtw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:sender:date:message-id:subject:from :to; bh=Kgsf1eMaam/R8Vw8rdpi37LBHaVJvCxqS+i6Q+4F+h8=; b=U32artorOoCw/qT8X2tqA3SQYaCR6wkVQ/x+MoMSZkdpVzbsOLZxOhXb6oApmYARcd gg73l6Xs6l+6tY539nqST8Ss67byhIGkreYCCCaYD4cVdoBJ6qxT5KcRYXFC7ErhK09C K7dSJe/qlzq9ZMyhkuzOOH4duhCiQFBJJN1XBEaEvOuck9jjyaV1nM+puiSGeTyjO4GX 46pX6lCgDbkPv4hKb35IgHrTLvBupCPVhcJ3fUo7CPl2QbrOe2S8WilL2deo9g+J9+7v 7SXQGxmvc2jkknfGDDDmugyU8mtJ/hA8EGqFkihk+fYcJ9Bxjdch6I3COCzayAwg5TPm Rcow== X-Gm-Message-State: AD7BkJKfbpMIEkIV4+ayeo/X2GJ6VAW6VN0cULdd2r2Q5ty5M2horvam4U3cCEk1HMX0MLaA6nK1MAIhvpkAKA== MIME-Version: 1.0 X-Received: by 10.60.116.169 with SMTP id jx9mr7062705oeb.30.1457120884016; Fri, 04 Mar 2016 11:48:04 -0800 (PST) Received: by 10.202.172.8 with HTTP; Fri, 4 Mar 2016 11:48:03 -0800 (PST) Date: Fri, 4 Mar 2016 11:48:03 -0800 X-Google-Sender-Auth: u71GJS4XfonIJhYQ5bY1N9CYRrk Message-ID: Subject: [PATCH] uClibc++: any throw statement causes memory corruption From: Ivan Koldaev To: uclibc@uclibc.org X-BeenThere: uclibc@uclibc.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "Discussion and development of uClibc \(the embedded C library\)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: uclibc-bounces@uclibc.org Sender: "uClibc" Patch for uClibc++ bug #8741 (https://bugs.busybox.net/show_bug.cgi?id=8741) 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 itself). 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. Signed-off-by: Ivan Kold --- include/unwind-cxx.h | 34 +++++++++++++++++++++++++++++++++- src/eh_alloc.cpp | 8 ++++---- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/include/unwind-cxx.h b/include/unwind-cxx.h index b773259..03e6428 100644 --- a/include/unwind-cxx.h +++ b/include/unwind-cxx.h @@ -1,5 +1,5 @@ // -*- C++ -*- Exception handling and frame unwind runtime interface routines. -// Copyright (C) 2001 Free Software Foundation, Inc. +// Copyright (C) 2001-2015 Free Software Foundation, Inc. // // This file is part of GCC. // @@ -13,6 +13,10 @@ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. +// // You should have received a copy of the GNU General Public License // along with GCC; see the file COPYING. If not, write to // the Free Software Foundation, 59 Temple Place - Suite 330, @@ -40,6 +44,12 @@ #include #include "unwind.h" +// Original unwind-cxx.h also includes bits/atomic_word.h which is CPU-specific, +// but always defines _Atomic_word as typedef int . +// Only thing that differs is memory-barrier macroses. +typedef int _Atomic_word; + + #pragma GCC visibility push(default) namespace __cxxabiv1 @@ -79,6 +89,13 @@ struct __cxa_exception _Unwind_Exception unwindHeader; }; +struct __cxa_refcounted_exception +{ + // Manage this header. + _Atomic_word referenceCount; + // __cxa_exception must be last, and no padding can be after it. + __cxa_exception exc; +}; // A dependent C++ exception object consists of a header, which is a wrapper // around an unwind object header with additional C++ specific information, @@ -210,6 +227,21 @@ __get_exception_header_from_ue (_Unwind_Exception *exc) return reinterpret_cast<__cxa_exception *>(exc + 1) - 1; } +// Acquire the C++ refcounted exception header from the C++ object. +static inline __cxa_refcounted_exception * +__get_refcounted_exception_header_from_obj (void *ptr) +{ + return reinterpret_cast<__cxa_refcounted_exception *>(ptr) - 1; +} + +// Acquire the C++ refcounted exception header from the generic exception +// header. +static inline __cxa_refcounted_exception * +__get_refcounted_exception_header_from_ue (_Unwind_Exception *exc) +{ + return reinterpret_cast<__cxa_refcounted_exception *>(exc + 1) - 1; +} + } /* namespace __cxxabiv1 */ #pragma GCC visibility pop diff --git a/src/eh_alloc.cpp b/src/eh_alloc.cpp index 5098196..5feeae9 100644 --- a/src/eh_alloc.cpp +++ b/src/eh_alloc.cpp @@ -30,16 +30,16 @@ extern "C" void * __cxa_allocate_exception(std::size_t thrown_size) throw(){ void *retval; //The sizeof crap is required by Itanium ABI because we need to provide space for //accounting information which is implementaion (gcc) specified - retval = malloc (thrown_size + sizeof(__cxa_exception)); + retval = malloc (thrown_size + sizeof(__cxa_refcounted_exception)); if (0 == retval){ std::terminate(); } - memset (retval, 0, sizeof(__cxa_exception)); - return (void *)((unsigned char *)retval + sizeof(__cxa_exception)); + memset (retval, 0, sizeof(__cxa_refcounted_exception)); + return (void *)((unsigned char *)retval + sizeof(__cxa_refcounted_exception)); } extern "C" void __cxa_free_exception(void *vptr) throw(){ - free( (char *)(vptr) - sizeof(__cxa_exception) ); + free( (char *)(vptr) - sizeof(__cxa_refcounted_exception) ); }