1*6b40e452SJens Wiklander /* SPDX-License-Identifier: BSD-3-Clause */ 2*6b40e452SJens Wiklander // Copyright 2019 The Fuchsia Authors. All rights reserved. 3*6b40e452SJens Wiklander // Use of this source code is governed by a BSD-style license that can be 4*6b40e452SJens Wiklander // found in the LICENSE file. 5*6b40e452SJens Wiklander 6*6b40e452SJens Wiklander /* 7*6b40e452SJens Wiklander * Content of LICENSE file mentioned above: 8*6b40e452SJens Wiklander Copyright 2019 The Fuchsia Authors. All rights reserved. 9*6b40e452SJens Wiklander Redistribution and use in source and binary forms, with or without 10*6b40e452SJens Wiklander modification, are permitted provided that the following conditions are 11*6b40e452SJens Wiklander met: 12*6b40e452SJens Wiklander * Redistributions of source code must retain the above copyright 13*6b40e452SJens Wiklander notice, this list of conditions and the following disclaimer. 14*6b40e452SJens Wiklander * Redistributions in binary form must reproduce the above 15*6b40e452SJens Wiklander copyright notice, this list of conditions and the following disclaimer 16*6b40e452SJens Wiklander in the documentation and/or other materials provided with the 17*6b40e452SJens Wiklander distribution. 18*6b40e452SJens Wiklander * Neither the name of Google Inc. nor the names of its 19*6b40e452SJens Wiklander contributors may be used to endorse or promote products derived from 20*6b40e452SJens Wiklander this software without specific prior written permission. 21*6b40e452SJens Wiklander THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22*6b40e452SJens Wiklander "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23*6b40e452SJens Wiklander LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24*6b40e452SJens Wiklander A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25*6b40e452SJens Wiklander OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26*6b40e452SJens Wiklander SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27*6b40e452SJens Wiklander LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28*6b40e452SJens Wiklander DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29*6b40e452SJens Wiklander THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30*6b40e452SJens Wiklander (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31*6b40e452SJens Wiklander OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32*6b40e452SJens Wiklander */ 33*6b40e452SJens Wiklander #ifndef FBL_CONFINE_ARRAY_INDEX_H_ 34*6b40e452SJens Wiklander #define FBL_CONFINE_ARRAY_INDEX_H_ 35*6b40e452SJens Wiklander 36*6b40e452SJens Wiklander #include <stddef.h> 37*6b40e452SJens Wiklander 38*6b40e452SJens Wiklander // confine_array_index() bounds-checks and sanitizes an array index safely in the presence of 39*6b40e452SJens Wiklander // speculative execution information leak bugs such as Spectre V1. confine_array_index() always 40*6b40e452SJens Wiklander // returns a sanitized index, even in speculative-path execution. 41*6b40e452SJens Wiklander // 42*6b40e452SJens Wiklander // Callers need to combine confine_array_index with a conventional bounds check; the bounds 43*6b40e452SJens Wiklander // check will return any necessary errors in the nonspeculative path, confine_array_index will 44*6b40e452SJens Wiklander // confine indexes in the speculative path. 45*6b40e452SJens Wiklander // 46*6b40e452SJens Wiklander // Use: 47*6b40e452SJens Wiklander // confine_array_index() returns |index|, if it is < size, or 0 if |index| is >= size. 48*6b40e452SJens Wiklander // 49*6b40e452SJens Wiklander // Example (may leak table1 contents): 50*6b40e452SJens Wiklander // 1: int lookup3(size_t index) { 51*6b40e452SJens Wiklander // 2: if (index >= table1_size) { 52*6b40e452SJens Wiklander // 3: return -1; 53*6b40e452SJens Wiklander // 4: } 54*6b40e452SJens Wiklander // 5: size_t index2 = table1[index]; 55*6b40e452SJens Wiklander // 6: return table2[index2]; 56*6b40e452SJens Wiklander // 7: } 57*6b40e452SJens Wiklander // 58*6b40e452SJens Wiklander // Converted: 59*6b40e452SJens Wiklander // 60*6b40e452SJens Wiklander // 1: int lookup3(size_t index) { 61*6b40e452SJens Wiklander // 2: if (index >= table1_size) { 62*6b40e452SJens Wiklander // 3: return -1; 63*6b40e452SJens Wiklander // 4: } 64*6b40e452SJens Wiklander // 5: size_t safe_index = confine_array_index(index, table1_size); 65*6b40e452SJens Wiklander // 6: size_t index2 = table1[safe_index]; 66*6b40e452SJens Wiklander // 7: return table2[index2]; 67*6b40e452SJens Wiklander // 8: } 68*6b40e452SJens Wiklander #ifdef __aarch64__ 69*6b40e452SJens Wiklander static inline size_t confine_array_index(size_t index, size_t size) { 70*6b40e452SJens Wiklander size_t safe_index; 71*6b40e452SJens Wiklander // Use a conditional select and a CSDB barrier to enforce validation of |index|. 72*6b40e452SJens Wiklander // See "Cache Speculation Side-channels" whitepaper, section "Software Mitigation". 73*6b40e452SJens Wiklander // "" The combination of both a conditional select/conditional move and the new barrier are 74*6b40e452SJens Wiklander // sufficient to address this problem on ALL Arm implementations... "" 75*6b40e452SJens Wiklander asm( 76*6b40e452SJens Wiklander "cmp %1, %2\n" // %1 holds the unsanitized index 77*6b40e452SJens Wiklander "csel %0, %1, xzr, lo\n" // Select index or zero based on carry (%1 within range) 78*6b40e452SJens Wiklander "csdb\n" 79*6b40e452SJens Wiklander : "=r"(safe_index) 80*6b40e452SJens Wiklander : "r"(index), "r"(size) 81*6b40e452SJens Wiklander : "cc"); 82*6b40e452SJens Wiklander return safe_index; 83*6b40e452SJens Wiklander } 84*6b40e452SJens Wiklander #endif 85*6b40e452SJens Wiklander #ifdef __x86_64__ 86*6b40e452SJens Wiklander static inline size_t confine_array_index(size_t index, size_t size) { 87*6b40e452SJens Wiklander size_t safe_index = 0; 88*6b40e452SJens Wiklander // Use a conditional move to enforce validation of |index|. 89*6b40e452SJens Wiklander // The conditional move has a data dependency on the result of a comparison and cannot 90*6b40e452SJens Wiklander // execute until the comparison is resolved. 91*6b40e452SJens Wiklander // See "Software Techniques for Managing Speculation on AMD Processors", Mitigation V1-2. 92*6b40e452SJens Wiklander // See "Analyzing potential bounds check bypass vulnerabilities", Revision 002, 93*6b40e452SJens Wiklander // Section 5.2 Bounds clipping 94*6b40e452SJens Wiklander __asm__( 95*6b40e452SJens Wiklander "cmp %1, %2\n" 96*6b40e452SJens Wiklander "cmova %1, %0\n" // Select between $0 and |index| 97*6b40e452SJens Wiklander : "+r"(safe_index) 98*6b40e452SJens Wiklander : "r"(index), "r"(size) 99*6b40e452SJens Wiklander : "cc"); 100*6b40e452SJens Wiklander return safe_index; 101*6b40e452SJens Wiklander } 102*6b40e452SJens Wiklander #endif 103*6b40e452SJens Wiklander #endif // FBL_CONFINE_ARRAY_INDEX_H_ 104