• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
9 namespace v8 {
10 namespace internal {
11 
12 // Randomly generated example key for simulating only.
13 const Simulator::PACKey Simulator::kPACKeyIB = {0xeebb163b474e04c8,
14                                                 0x5267ac6fc280fb7c, 1};
15 
16 namespace {
17 
GetNibble(uint64_t in_data,int position)18 uint64_t GetNibble(uint64_t in_data, int position) {
19   return (in_data >> position) & 0xf;
20 }
21 
PACCellShuffle(uint64_t in_data)22 uint64_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 
PACCellInvShuffle(uint64_t in_data)32 uint64_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 
RotCell(uint64_t in_cell,int amount)42 uint64_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 
PACMult(uint64_t s_input)50 uint64_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 
PACSub(uint64_t t_input)76 uint64_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 
PACInvSub(uint64_t t_input)87 uint64_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 
TweakCellInvRot(uint64_t in_cell)98 uint64_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 
TweakInvShuffle(uint64_t in_data)105 uint64_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 
TweakCellRot(uint64_t in_cell)122 uint64_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 
TweakShuffle(uint64_t in_data)129 uint64_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.
ComputePAC(uint64_t data,uint64_t context,PACKey key)152 uint64_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.
CalculatePACMask(uint64_t ptr,PointerType type,int ttbr)211 uint64_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 
AuthPAC(uint64_t ptr,uint64_t context,PACKey key,PointerType type)219 uint64_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 
AddPAC(uint64_t ptr,uint64_t context,PACKey key,PointerType type)242 uint64_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 
StripPAC(uint64_t ptr,PointerType type)264 uint64_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