From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gnu.wildebeest.org (gnu.wildebeest.org [45.83.234.184]) by sourceware.org (Postfix) with ESMTPS id 1566C3858D32 for ; Sat, 11 Feb 2023 23:42:59 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1566C3858D32 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=klomp.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=klomp.org Received: by gnu.wildebeest.org (Postfix, from userid 1000) id 2D79230067D8; Sun, 12 Feb 2023 00:42:58 +0100 (CET) Date: Sun, 12 Feb 2023 00:42:58 +0100 From: Mark Wielaard To: vvvvvv@google.com Cc: elfutils-devel@sourceware.org, kernel-team@android.com, maennich@google.com Subject: Re: [PATCH] libdw: check memory access in get_(u|s)leb128 Message-ID: <20230211234258.GG2430@gnu.wildebeest.org> References: <20230125160530.949622-1-vvvvvv@google.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20230125160530.949622-1-vvvvvv@google.com> User-Agent: Mutt/1.5.21 (2010-09-15) X-Spam-Status: No, score=-3037.2 required=5.0 tests=BAYES_00,GIT_PATCH_0,JMQ_SPF_NEUTRAL,KAM_DMARC_STATUS,KAM_NUMSUBJECT,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: Hi Aleksei, On Wed, Jan 25, 2023 at 04:05:30PM +0000, Aleksei Vetrov via Elfutils-devel wrote: > From: Aleksei Vetrov > > __libdw_get_uleb128 and __libdw_get_sleb128 should check if addrp has > already reached the end before unrolling the first step. It is done by > moving __libdw_max_len to the beginning of the function, which already > has all the checks. I did some performance tests and couldn't find any significant change. Even with my other extra checks added in libdw and readelf. One question about the sleb128 case though: > static inline int64_t > __libdw_get_sleb128 (const unsigned char **addrp, const unsigned char *end) > { > + const size_t max = __libdw_max_len_sleb128 (*addrp, end); > /* Do the work in an unsigned type, but use implementation-defined > behavior to cast to signed on return. This avoids some undefined > behavior when shifting. */ > @@ -131,9 +133,9 @@ __libdw_get_sleb128 (const unsigned char **addrp, const unsigned char *end) > > /* Unroll the first step to help the compiler optimize > for the common single-byte case. */ > - get_sleb128_step (acc, *addrp, 0); > + if (likely (max > 0)) > + get_sleb128_step (acc, *addrp, 0); > > - const size_t max = __libdw_max_len_sleb128 (*addrp - 1, end); > for (size_t i = 1; i < max; ++i) > get_sleb128_step (acc, *addrp, i); > if (*addrp == end) But what about the case where *addrp > end? After this code we will do: /* There might be one extra byte. */ unsigned char b = **addrp; ++*addrp; So I think we want to catch that too. Easiest imho seems to move (and invert) the max check immediately after calculating max: diff --git a/libdw/memory-access.h b/libdw/memory-access.h index 1cac6af3..72348623 100644 --- a/libdw/memory-access.h +++ b/libdw/memory-access.h @@ -126,6 +126,9 @@ static inline int64_t __libdw_get_sleb128 (const unsigned char **addrp, const unsigned char *end) { const size_t max = __libdw_max_len_sleb128 (*addrp, end); + if (unlikely (max == 0)) + return INT64_MAX; + /* Do the work in an unsigned type, but use implementation-defined behavior to cast to signed on return. This avoids some undefined behavior when shifting. */ @@ -133,8 +136,7 @@ __libdw_get_sleb128 (const unsigned char **addrp, const unsigned char *end) /* Unroll the first step to help the compiler optimize for the common single-byte case. */ - if (likely (max > 0)) - get_sleb128_step (acc, *addrp, 0); + get_sleb128_step (acc, *addrp, 0); for (size_t i = 1; i < max; ++i) get_sleb128_step (acc, *addrp, i); Cheers, Mark