1// Copyright 2019 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "src/execution/arm64/simulator-arm64.h" 6 7#if defined(USE_SIMULATOR) 8 9namespace v8 { 10namespace internal { 11 12// Randomly generated example key for simulating only. 13const Simulator::PACKey Simulator::kPACKeyIB = {0xeebb163b474e04c8, 14 0x5267ac6fc280fb7c, 1}; 15 16namespace { 17 18uint64_t GetNibble(uint64_t in_data, int position) { 19 return (in_data >> position) & 0xf; 20} 21 22uint64_t PACCellShuffle(uint64_t in_data) { 23 static int in_positions[16] = {52, 24, 44, 0, 28, 48, 4, 40, 24 32, 12, 56, 20, 8, 36, 16, 60}; 25 uint64_t out_data = 0; 26 for (int i = 0; i < 16; ++i) { 27 out_data |= GetNibble(in_data, in_positions[i]) << (4 * i); 28 } 29 return out_data; 30} 31 32uint64_t PACCellInvShuffle(uint64_t in_data) { 33 static int in_positions[16] = {12, 24, 48, 36, 56, 44, 4, 16, 34 32, 52, 28, 8, 20, 0, 40, 60}; 35 uint64_t out_data = 0; 36 for (int i = 0; i < 16; ++i) { 37 out_data |= GetNibble(in_data, in_positions[i]) << (4 * i); 38 } 39 return out_data; 40} 41 42uint64_t RotCell(uint64_t in_cell, int amount) { 43 DCHECK((amount >= 1) && (amount <= 3)); 44 45 in_cell &= 0xf; 46 uint8_t temp = in_cell << 4 | in_cell; 47 return static_cast<uint64_t>((temp >> (4 - amount)) & 0xf); 48} 49 50uint64_t PACMult(uint64_t s_input) { 51 uint8_t t0; 52 uint8_t t1; 53 uint8_t t2; 54 uint8_t t3; 55 uint64_t s_output = 0; 56 57 for (int i = 0; i < 4; ++i) { 58 uint8_t s12 = (s_input >> (4 * (i + 12))) & 0xf; 59 uint8_t s8 = (s_input >> (4 * (i + 8))) & 0xf; 60 uint8_t s4 = (s_input >> (4 * (i + 4))) & 0xf; 61 uint8_t s0 = (s_input >> (4 * (i + 0))) & 0xf; 62 63 t0 = RotCell(s8, 1) ^ RotCell(s4, 2) ^ RotCell(s0, 1); 64 t1 = RotCell(s12, 1) ^ RotCell(s4, 1) ^ RotCell(s0, 2); 65 t2 = RotCell(s12, 2) ^ RotCell(s8, 1) ^ RotCell(s0, 1); 66 t3 = RotCell(s12, 1) ^ RotCell(s8, 2) ^ RotCell(s4, 1); 67 68 s_output |= static_cast<uint64_t>(t3) << (4 * (i + 0)); 69 s_output |= static_cast<uint64_t>(t2) << (4 * (i + 4)); 70 s_output |= static_cast<uint64_t>(t1) << (4 * (i + 8)); 71 s_output |= static_cast<uint64_t>(t0) << (4 * (i + 12)); 72 } 73 return s_output; 74} 75 76uint64_t PACSub(uint64_t t_input) { 77 uint64_t t_output = 0; 78 uint8_t substitutions[16] = {0xb, 0x6, 0x8, 0xf, 0xc, 0x0, 0x9, 0xe, 79 0x3, 0x7, 0x4, 0x5, 0xd, 0x2, 0x1, 0xa}; 80 for (int i = 0; i < 16; ++i) { 81 unsigned index = ((t_input >> (4 * i)) & 0xf); 82 t_output |= static_cast<uint64_t>(substitutions[index]) << (4 * i); 83 } 84 return t_output; 85} 86 87uint64_t PACInvSub(uint64_t t_input) { 88 uint64_t t_output = 0; 89 uint8_t substitutions[16] = {0x5, 0xe, 0xd, 0x8, 0xa, 0xb, 0x1, 0x9, 90 0x2, 0x6, 0xf, 0x0, 0x4, 0xc, 0x7, 0x3}; 91 for (int i = 0; i < 16; ++i) { 92 unsigned index = ((t_input >> (4 * i)) & 0xf); 93 t_output |= static_cast<uint64_t>(substitutions[index]) << (4 * i); 94 } 95 return t_output; 96} 97 98uint64_t TweakCellInvRot(uint64_t in_cell) { 99 uint64_t out_cell = 0; 100 out_cell |= (in_cell & 0x7) << 1; 101 out_cell |= (in_cell & 0x1) ^ ((in_cell >> 3) & 0x1); 102 return out_cell; 103} 104 105uint64_t TweakInvShuffle(uint64_t in_data) { 106 uint64_t out_data = 0; 107 out_data |= TweakCellInvRot(in_data >> 48) << 0; 108 out_data |= ((in_data >> 52) & 0xf) << 4; 109 out_data |= ((in_data >> 20) & 0xff) << 8; 110 out_data |= ((in_data >> 0) & 0xff) << 16; 111 out_data |= TweakCellInvRot(in_data >> 8) << 24; 112 out_data |= ((in_data >> 12) & 0xf) << 28; 113 out_data |= TweakCellInvRot(in_data >> 28) << 32; 114 out_data |= TweakCellInvRot(in_data >> 60) << 36; 115 out_data |= TweakCellInvRot(in_data >> 56) << 40; 116 out_data |= TweakCellInvRot(in_data >> 16) << 44; 117 out_data |= ((in_data >> 32) & 0xfff) << 48; 118 out_data |= TweakCellInvRot(in_data >> 44) << 60; 119 return out_data; 120} 121 122uint64_t TweakCellRot(uint64_t in_cell) { 123 uint64_t out_cell = 0; 124 out_cell |= ((in_cell & 0x1) ^ ((in_cell >> 1) & 0x1)) << 3; 125 out_cell |= (in_cell >> 0x1) & 0x7; 126 return out_cell; 127} 128 129uint64_t TweakShuffle(uint64_t in_data) { 130 uint64_t out_data = 0; 131 out_data |= ((in_data >> 16) & 0xff) << 0; 132 out_data |= TweakCellRot(in_data >> 24) << 8; 133 out_data |= ((in_data >> 28) & 0xf) << 12; 134 out_data |= TweakCellRot(in_data >> 44) << 16; 135 out_data |= ((in_data >> 8) & 0xff) << 20; 136 out_data |= TweakCellRot(in_data >> 32) << 28; 137 out_data |= ((in_data >> 48) & 0xfff) << 32; 138 out_data |= TweakCellRot(in_data >> 60) << 44; 139 out_data |= TweakCellRot(in_data >> 0) << 48; 140 out_data |= ((in_data >> 4) & 0xf) << 52; 141 out_data |= TweakCellRot(in_data >> 40) << 56; 142 out_data |= TweakCellRot(in_data >> 36) << 60; 143 return out_data; 144} 145 146} // namespace 147 148// For a description of QARMA see: 149// The QARMA Block Cipher Family, Roberto Avanzi, Qualcomm Product Security 150// Initiative. 151// The pseudocode is available in ARM DDI 0487D.b, J1-6946. 152uint64_t Simulator::ComputePAC(uint64_t data, uint64_t context, PACKey key) { 153 uint64_t key0 = key.high; 154 uint64_t key1 = key.low; 155 const uint64_t RC[5] = {0x0000000000000000, 0x13198a2e03707344, 156 0xa4093822299f31d0, 0x082efa98ec4e6c89, 157 0x452821e638d01377}; 158 const uint64_t Alpha = 0xc0ac29B7c97c50dd; 159 160 uint64_t modk0 = ((key0 & 0x1) << 63) | ((key0 >> 2) << 1) | 161 ((key0 >> 63) ^ ((key0 >> 1) & 0x1)); 162 uint64_t running_mod = context; 163 uint64_t working_val = data ^ key0; 164 uint64_t round_key; 165 for (int i = 0; i < 5; ++i) { 166 round_key = key1 ^ running_mod; 167 working_val ^= round_key; 168 working_val ^= RC[i]; 169 if (i > 0) { 170 working_val = PACCellShuffle(working_val); 171 working_val = PACMult(working_val); 172 } 173 working_val = PACSub(working_val); 174 running_mod = TweakShuffle(running_mod); 175 } 176 177 round_key = modk0 ^ running_mod; 178 working_val ^= round_key; 179 working_val = PACCellShuffle(working_val); 180 working_val = PACMult(working_val); 181 working_val = PACSub(working_val); 182 working_val = PACCellShuffle(working_val); 183 working_val = PACMult(working_val); 184 working_val ^= key1; 185 working_val = PACCellInvShuffle(working_val); 186 working_val = PACInvSub(working_val); 187 working_val = PACMult(working_val); 188 working_val = PACCellInvShuffle(working_val); 189 working_val ^= key0; 190 working_val ^= running_mod; 191 192 for (int i = 0; i < 5; ++i) { 193 working_val = PACInvSub(working_val); 194 if (i < 4) { 195 working_val = PACMult(working_val); 196 working_val = PACCellInvShuffle(working_val); 197 } 198 running_mod = TweakInvShuffle(running_mod); 199 round_key = key1 ^ running_mod; 200 working_val ^= RC[4 - i]; 201 working_val ^= round_key; 202 working_val ^= Alpha; 203 } 204 205 return working_val ^ modk0; 206} 207 208// The TTBR is selected by bit 63 or 55 depending on TBI for pointers without 209// codes, but is always 55 once a PAC code is added to a pointer. For this 210// reason, it must be calculated at the call site. 211uint64_t Simulator::CalculatePACMask(uint64_t ptr, PointerType type, int ttbr) { 212 int bottom_pac_bit = GetBottomPACBit(ptr, ttbr); 213 int top_pac_bit = GetTopPACBit(ptr, type); 214 return unsigned_bitextract_64(top_pac_bit, bottom_pac_bit, 215 0xffffffffffffffff & ~kTTBRMask) 216 << bottom_pac_bit; 217} 218 219uint64_t Simulator::AuthPAC(uint64_t ptr, uint64_t context, PACKey key, 220 PointerType type) { 221 DCHECK((key.number == 0) || (key.number == 1)); 222 223 uint64_t pac_mask = CalculatePACMask(ptr, type, (ptr >> 55) & 1); 224 uint64_t original_ptr = 225 ((ptr & kTTBRMask) == 0) ? (ptr & ~pac_mask) : (ptr | pac_mask); 226 227 uint64_t pac = ComputePAC(original_ptr, context, key); 228 229 uint64_t error_code = UINT64_C(1) << key.number; 230 if ((pac & pac_mask) == (ptr & pac_mask)) { 231 return original_ptr; 232 } else { 233 int error_lsb = GetTopPACBit(ptr, type) - 2; 234 uint64_t error_mask = UINT64_C(0x3) << error_lsb; 235 if (FLAG_sim_abort_on_bad_auth) { 236 FATAL("Pointer authentication failure."); 237 } 238 return (original_ptr & ~error_mask) | (error_code << error_lsb); 239 } 240} 241 242uint64_t Simulator::AddPAC(uint64_t ptr, uint64_t context, PACKey key, 243 PointerType type) { 244 int top_pac_bit = GetTopPACBit(ptr, type); 245 246 DCHECK(HasTBI(ptr, type)); 247 int ttbr = (ptr >> 55) & 1; 248 uint64_t pac_mask = CalculatePACMask(ptr, type, ttbr); 249 uint64_t ext_ptr = (ttbr == 0) ? (ptr & ~pac_mask) : (ptr | pac_mask); 250 251 uint64_t pac = ComputePAC(ext_ptr, context, key); 252 253 // If the pointer isn't all zeroes or all ones in the PAC bitfield, corrupt 254 // the resulting code. 255 if (((ptr & (pac_mask | kTTBRMask)) != 0x0) && 256 ((~ptr & (pac_mask | kTTBRMask)) != 0x0)) { 257 pac ^= UINT64_C(1) << (top_pac_bit - 1); 258 } 259 260 uint64_t ttbr_shifted = static_cast<uint64_t>(ttbr) << 55; 261 return (pac & pac_mask) | ttbr_shifted | (ptr & ~pac_mask); 262} 263 264uint64_t Simulator::StripPAC(uint64_t ptr, PointerType type) { 265 uint64_t pac_mask = CalculatePACMask(ptr, type, (ptr >> 55) & 1); 266 return ((ptr & kTTBRMask) == 0) ? (ptr & ~pac_mask) : (ptr | pac_mask); 267} 268 269} // namespace internal 270} // namespace v8 271 272#endif // USE_SIMULATOR 273