From owner-svn-src-head@freebsd.org Mon Dec 14 00:48:00 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 0C9154A92EC; Mon, 14 Dec 2020 00:48:00 +0000 (UTC) (envelope-from jrtc27@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 4CvN676yyVz3jH1; Mon, 14 Dec 2020 00:47:59 +0000 (UTC) (envelope-from jrtc27@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 E273F18F2E; Mon, 14 Dec 2020 00:47:59 +0000 (UTC) (envelope-from jrtc27@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 0BE0lxjk041421; Mon, 14 Dec 2020 00:47:59 GMT (envelope-from jrtc27@FreeBSD.org) Received: (from jrtc27@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 0BE0lx9N041420; Mon, 14 Dec 2020 00:47:59 GMT (envelope-from jrtc27@FreeBSD.org) Message-Id: <202012140047.0BE0lx9N041420@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: jrtc27 set sender to jrtc27@FreeBSD.org using -f From: Jessica Clarke Date: Mon, 14 Dec 2020 00:47:59 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r368624 - head/sys/mips/mips X-SVN-Group: head X-SVN-Commit-Author: jrtc27 X-SVN-Commit-Paths: head/sys/mips/mips X-SVN-Commit-Revision: 368624 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: Mon, 14 Dec 2020 00:48:00 -0000 Author: jrtc27 Date: Mon Dec 14 00:47:59 2020 New Revision: 368624 URL: https://svnweb.freebsd.org/changeset/base/368624 Log: mips: Fix sub-word atomics implementation These aligned the address but then always used the least significant bits of the value in memory, which is the wrong half 50% of the time for 16-bit atomics and the wrong quarter 75% of the time for 8-bit atomics. These bugs were all present in r178172, the commit that added the mips port, and have remained for its entire existence to date. Reviewed by: jhb (mentor) Approved by: jhb (mentor) Differential Revision: https://reviews.freebsd.org/D27343 Modified: head/sys/mips/mips/support.S Modified: head/sys/mips/mips/support.S ============================================================================== --- head/sys/mips/mips/support.S Mon Dec 14 00:46:24 2020 (r368623) +++ head/sys/mips/mips/support.S Mon Dec 14 00:47:59 2020 (r368624) @@ -90,6 +90,7 @@ #include #include #include +#include #include #include #include @@ -578,9 +579,14 @@ END(ffs) */ LEAF(atomic_set_16) .set noreorder - srl a0, a0, 2 # round down address to be 32-bit aligned - sll a0, a0, 2 - andi a1, a1, 0xffff + /* NB: Only bit 1 is masked so the ll catches unaligned inputs */ + andi t0, a0, 2 # get unaligned offset + xor a0, a0, t0 # align pointer +#if _BYTE_ORDER == BIG_ENDIAN + xori t0, t0, 2 +#endif + sll t0, t0, 3 # convert byte offset to bit offset + sll a1, a1, t0 # put bits in the right half 1: ll t0, 0(a0) or t0, t0, a1 @@ -600,17 +606,18 @@ END(atomic_set_16) */ LEAF(atomic_clear_16) .set noreorder - srl a0, a0, 2 # round down address to be 32-bit aligned - sll a0, a0, 2 - nor a1, zero, a1 + /* NB: Only bit 1 is masked so the ll catches unaligned inputs */ + andi t0, a0, 2 # get unaligned offset + xor a0, a0, t0 # align pointer +#if _BYTE_ORDER == BIG_ENDIAN + xori t0, t0, 2 +#endif + sll t0, t0, 3 # convert byte offset to bit offset + sll a1, a1, t0 # put bits in the right half + not a1, a1 1: ll t0, 0(a0) - move t1, t0 - andi t1, t1, 0xffff # t1 has the original lower 16 bits - and t1, t1, a1 # t1 has the new lower 16 bits - srl t0, t0, 16 # preserve original top 16 bits - sll t0, t0, 16 - or t0, t0, t1 + and t0, t0, a1 sc t0, 0(a0) beq t0, zero, 1b nop @@ -628,17 +635,23 @@ END(atomic_clear_16) */ LEAF(atomic_subtract_16) .set noreorder - srl a0, a0, 2 # round down address to be 32-bit aligned - sll a0, a0, 2 + /* NB: Only bit 1 is masked so the ll catches unaligned inputs */ + andi t0, a0, 2 # get unaligned offset + xor a0, a0, t0 # align pointer +#if _BYTE_ORDER == BIG_ENDIAN + xori t0, t0, 2 # flip order for big-endian +#endif + sll t0, t0, 3 # convert byte offset to bit offset + sll a1, a1, t0 # put bits in the right half + li t2, 0xffff + sll t2, t2, t0 # compute mask 1: ll t0, 0(a0) - move t1, t0 - andi t1, t1, 0xffff # t1 has the original lower 16 bits - subu t1, t1, a1 - andi t1, t1, 0xffff # t1 has the new lower 16 bits - srl t0, t0, 16 # preserve original top 16 bits - sll t0, t0, 16 - or t0, t0, t1 + subu t1, t0, a1 + /* Exploit ((t0 & ~t2) | (t1 & t2)) = t0 ^ ((t0 ^ t1) & t2) */ + xor t1, t0, t1 + and t1, t1, t2 + xor t0, t0, t1 sc t0, 0(a0) beq t0, zero, 1b nop @@ -655,17 +668,23 @@ END(atomic_subtract_16) */ LEAF(atomic_add_16) .set noreorder - srl a0, a0, 2 # round down address to be 32-bit aligned - sll a0, a0, 2 + /* NB: Only bit 1 is masked so the ll catches unaligned inputs */ + andi t0, a0, 2 # get unaligned offset + xor a0, a0, t0 # align pointer +#if _BYTE_ORDER == BIG_ENDIAN + xori t0, t0, 2 # flip order for big-endian +#endif + sll t0, t0, 3 # convert byte offset to bit offset + sll a1, a1, t0 # put bits in the right half + li t2, 0xffff + sll t2, t2, t0 # compute mask 1: ll t0, 0(a0) - move t1, t0 - andi t1, t1, 0xffff # t1 has the original lower 16 bits - addu t1, t1, a1 - andi t1, t1, 0xffff # t1 has the new lower 16 bits - srl t0, t0, 16 # preserve original top 16 bits - sll t0, t0, 16 - or t0, t0, t1 + addu t1, t0, a1 + /* Exploit ((t0 & ~t2) | (t1 & t2)) = t0 ^ ((t0 ^ t1) & t2) */ + xor t1, t0, t1 + and t1, t1, t2 + xor t0, t0, t1 sc t0, 0(a0) beq t0, zero, 1b nop @@ -682,17 +701,22 @@ END(atomic_add_16) */ LEAF(atomic_add_8) .set noreorder - srl a0, a0, 2 # round down address to be 32-bit aligned - sll a0, a0, 2 + andi t0, a0, 3 # get unaligned offset + xor a0, a0, t0 # align pointer +#if _BYTE_ORDER == BIG_ENDIAN + xori t0, t0, 3 # flip order for big-endian +#endif + sll t0, t0, 3 # convert byte offset to bit offset + sll a1, a1, t0 # put bits in the right quarter + li t2, 0xff + sll t2, t2, t0 # compute mask 1: ll t0, 0(a0) - move t1, t0 - andi t1, t1, 0xff # t1 has the original lower 8 bits - addu t1, t1, a1 - andi t1, t1, 0xff # t1 has the new lower 8 bits - srl t0, t0, 8 # preserve original top 24 bits - sll t0, t0, 8 - or t0, t0, t1 + addu t1, t0, a1 + /* Exploit ((t0 & ~t2) | (t1 & t2)) = t0 ^ ((t0 ^ t1) & t2) */ + xor t1, t0, t1 + and t1, t1, t2 + xor t0, t0, t1 sc t0, 0(a0) beq t0, zero, 1b nop @@ -710,17 +734,22 @@ END(atomic_add_8) */ LEAF(atomic_subtract_8) .set noreorder - srl a0, a0, 2 # round down address to be 32-bit aligned - sll a0, a0, 2 + andi t0, a0, 3 # get unaligned offset + xor a0, a0, t0 # align pointer +#if _BYTE_ORDER == BIG_ENDIAN + xori t0, t0, 3 # flip order for big-endian +#endif + sll t0, t0, 3 # convert byte offset to bit offset + sll a1, a1, t0 # put bits in the right quarter + li t2, 0xff + sll t2, t2, t0 # compute mask 1: ll t0, 0(a0) - move t1, t0 - andi t1, t1, 0xff # t1 has the original lower 8 bits - subu t1, t1, a1 - andi t1, t1, 0xff # t1 has the new lower 8 bits - srl t0, t0, 8 # preserve original top 24 bits - sll t0, t0, 8 - or t0, t0, t1 + subu t1, t0, a1 + /* Exploit ((t0 & ~t2) | (t1 & t2)) = t0 ^ ((t0 ^ t1) & t2) */ + xor t1, t0, t1 + and t1, t1, t2 + xor t0, t0, t1 sc t0, 0(a0) beq t0, zero, 1b nop