From owner-svn-src-head@freebsd.org Thu Nov 19 00:03:15 2020 Return-Path: Delivered-To: svn-src-head@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id E6F624755F9; Thu, 19 Nov 2020 00:03:15 +0000 (UTC) (envelope-from emaste@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Cc0J366rSz4qYJ; Thu, 19 Nov 2020 00:03:15 +0000 (UTC) (envelope-from emaste@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id C507E1A8A8; Thu, 19 Nov 2020 00:03:15 +0000 (UTC) (envelope-from emaste@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 0AJ03F05066256; Thu, 19 Nov 2020 00:03:15 GMT (envelope-from emaste@FreeBSD.org) Received: (from emaste@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 0AJ03FLI066255; Thu, 19 Nov 2020 00:03:15 GMT (envelope-from emaste@FreeBSD.org) Message-Id: <202011190003.0AJ03FLI066255@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: emaste set sender to emaste@FreeBSD.org using -f From: Ed Maste Date: Thu, 19 Nov 2020 00:03:15 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r367823 - head/lib/libc/string X-SVN-Group: head X-SVN-Commit-Author: emaste X-SVN-Commit-Paths: head/lib/libc/string X-SVN-Commit-Revision: 367823 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 19 Nov 2020 00:03:16 -0000 Author: emaste Date: Thu Nov 19 00:03:15 2020 New Revision: 367823 URL: https://svnweb.freebsd.org/changeset/base/367823 Log: libc: fix undefined behavior from signed overflow in strstr and memmem unsigned char promotes to int, which can overflow when shifted left by 24 bits or more. this has been reported multiple times but then forgotten. it's expected to be benign UB, but can trap when built with explicit overflow catching (ubsan or similar). fix it now. note that promotion to uint32_t is safe and portable even outside of the assumptions usually made in musl, since either uint32_t has rank at least unsigned int, so that no further default promotions happen, or int is wide enough that the shift can't overflow. this is a desirable property to have in case someone wants to reuse the code elsewhere. musl commit: 593caa456309714402ca4cb77c3770f4c24da9da Obtained from: musl Modified: head/lib/libc/string/memmem.c head/lib/libc/string/strstr.c Modified: head/lib/libc/string/memmem.c ============================================================================== --- head/lib/libc/string/memmem.c Thu Nov 19 00:02:12 2020 (r367822) +++ head/lib/libc/string/memmem.c Thu Nov 19 00:03:15 2020 (r367823) @@ -41,8 +41,8 @@ twobyte_memmem(const unsigned char *h, size_t k, const static char * threebyte_memmem(const unsigned char *h, size_t k, const unsigned char *n) { - uint32_t nw = n[0] << 24 | n[1] << 16 | n[2] << 8; - uint32_t hw = h[0] << 24 | h[1] << 16 | h[2] << 8; + uint32_t nw = (uint32_t)n[0] << 24 | n[1] << 16 | n[2] << 8; + uint32_t hw = (uint32_t)h[0] << 24 | h[1] << 16 | h[2] << 8; for (h += 3, k -= 3; k; k--, hw = (hw | *h++) << 8) if (hw == nw) return (char *)h - 3; @@ -52,8 +52,8 @@ threebyte_memmem(const unsigned char *h, size_t k, con static char * fourbyte_memmem(const unsigned char *h, size_t k, const unsigned char *n) { - uint32_t nw = n[0] << 24 | n[1] << 16 | n[2] << 8 | n[3]; - uint32_t hw = h[0] << 24 | h[1] << 16 | h[2] << 8 | h[3]; + uint32_t nw = (uint32_t)n[0] << 24 | n[1] << 16 | n[2] << 8 | n[3]; + uint32_t hw = (uint32_t)h[0] << 24 | h[1] << 16 | h[2] << 8 | h[3]; for (h += 4, k -= 4; k; k--, hw = hw << 8 | *h++) if (hw == nw) return (char *)h - 4; Modified: head/lib/libc/string/strstr.c ============================================================================== --- head/lib/libc/string/strstr.c Thu Nov 19 00:02:12 2020 (r367822) +++ head/lib/libc/string/strstr.c Thu Nov 19 00:03:15 2020 (r367823) @@ -40,8 +40,8 @@ twobyte_strstr(const unsigned char *h, const unsigned static char * threebyte_strstr(const unsigned char *h, const unsigned char *n) { - uint32_t nw = n[0] << 24 | n[1] << 16 | n[2] << 8; - uint32_t hw = h[0] << 24 | h[1] << 16 | h[2] << 8; + uint32_t nw = (uint32_t)n[0] << 24 | n[1] << 16 | n[2] << 8; + uint32_t hw = (uint32_t)h[0] << 24 | h[1] << 16 | h[2] << 8; for (h += 2; *h && hw != nw; hw = (hw | *++h) << 8) ; return *h ? (char *)h - 2 : 0; @@ -50,8 +50,8 @@ threebyte_strstr(const unsigned char *h, const unsigne static char * fourbyte_strstr(const unsigned char *h, const unsigned char *n) { - uint32_t nw = n[0] << 24 | n[1] << 16 | n[2] << 8 | n[3]; - uint32_t hw = h[0] << 24 | h[1] << 16 | h[2] << 8 | h[3]; + uint32_t nw = (uint32_t)n[0] << 24 | n[1] << 16 | n[2] << 8 | n[3]; + uint32_t hw = (uint32_t)h[0] << 24 | h[1] << 16 | h[2] << 8 | h[3]; for (h += 3; *h && hw != nw; hw = hw << 8 | *++h) ; return *h ? (char *)h - 3 : 0;