1 /* Copyright (c) 2016, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15 #include <openssl/cpu.h>
16
17 #if defined(OPENSSL_ARM) && !defined(OPENSSL_STATIC_ARMCAP)
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <string.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24
25 #include <openssl/arm_arch.h>
26 #include <openssl/buf.h>
27 #include <openssl/mem.h>
28
29 #include "internal.h"
30
31
32 #define AT_HWCAP 16
33 #define AT_HWCAP2 26
34
35 #define HWCAP_NEON (1 << 12)
36
37 /* See /usr/include/asm/hwcap.h on an ARM installation for the source of
38 * these values. */
39 #define HWCAP2_AES (1 << 0)
40 #define HWCAP2_PMULL (1 << 1)
41 #define HWCAP2_SHA1 (1 << 2)
42 #define HWCAP2_SHA2 (1 << 3)
43
44 /* |getauxval| is not available on Android until API level 20. Link it as a weak
45 * symbol and use other methods as fallback. */
46 unsigned long getauxval(unsigned long type) __attribute__((weak));
47
open_eintr(const char * path,int flags)48 static int open_eintr(const char *path, int flags) {
49 int ret;
50 do {
51 ret = open(path, flags);
52 } while (ret < 0 && errno == EINTR);
53 return ret;
54 }
55
read_eintr(int fd,void * out,size_t len)56 static ssize_t read_eintr(int fd, void *out, size_t len) {
57 ssize_t ret;
58 do {
59 ret = read(fd, out, len);
60 } while (ret < 0 && errno == EINTR);
61 return ret;
62 }
63
64 /* read_full reads exactly |len| bytes from |fd| to |out|. On error or end of
65 * file, it returns zero. */
read_full(int fd,void * out,size_t len)66 static int read_full(int fd, void *out, size_t len) {
67 char *outp = out;
68 while (len > 0) {
69 ssize_t ret = read_eintr(fd, outp, len);
70 if (ret <= 0) {
71 return 0;
72 }
73 outp += ret;
74 len -= ret;
75 }
76 return 1;
77 }
78
79 /* read_file opens |path| and reads until end-of-file. On success, it returns
80 * one and sets |*out_ptr| and |*out_len| to a newly-allocated buffer with the
81 * contents. Otherwise, it returns zero. */
read_file(char ** out_ptr,size_t * out_len,const char * path)82 static int read_file(char **out_ptr, size_t *out_len, const char *path) {
83 int fd = open_eintr(path, O_RDONLY);
84 if (fd < 0) {
85 return 0;
86 }
87
88 static const size_t kReadSize = 1024;
89 int ret = 0;
90 size_t cap = kReadSize, len = 0;
91 char *buf = OPENSSL_malloc(cap);
92 if (buf == NULL) {
93 goto err;
94 }
95
96 for (;;) {
97 if (cap - len < kReadSize) {
98 size_t new_cap = cap * 2;
99 if (new_cap < cap) {
100 goto err;
101 }
102 char *new_buf = OPENSSL_realloc(buf, new_cap);
103 if (new_buf == NULL) {
104 goto err;
105 }
106 buf = new_buf;
107 cap = new_cap;
108 }
109
110 ssize_t bytes_read = read_eintr(fd, buf + len, kReadSize);
111 if (bytes_read < 0) {
112 goto err;
113 }
114 if (bytes_read == 0) {
115 break;
116 }
117 len += bytes_read;
118 }
119
120 *out_ptr = buf;
121 *out_len = len;
122 ret = 1;
123 buf = NULL;
124
125 err:
126 OPENSSL_free(buf);
127 close(fd);
128 return ret;
129 }
130
131 /* getauxval_proc behaves like |getauxval| but reads from /proc/self/auxv. */
getauxval_proc(unsigned long type)132 static unsigned long getauxval_proc(unsigned long type) {
133 int fd = open_eintr("/proc/self/auxv", O_RDONLY);
134 if (fd < 0) {
135 return 0;
136 }
137
138 struct {
139 unsigned long tag;
140 unsigned long value;
141 } entry;
142
143 for (;;) {
144 if (!read_full(fd, &entry, sizeof(entry)) ||
145 (entry.tag == 0 && entry.value == 0)) {
146 break;
147 }
148 if (entry.tag == type) {
149 close(fd);
150 return entry.value;
151 }
152 }
153 close(fd);
154 return 0;
155 }
156
157 typedef struct {
158 const char *data;
159 size_t len;
160 } STRING_PIECE;
161
STRING_PIECE_equals(const STRING_PIECE * a,const char * b)162 static int STRING_PIECE_equals(const STRING_PIECE *a, const char *b) {
163 size_t b_len = strlen(b);
164 return a->len == b_len && OPENSSL_memcmp(a->data, b, b_len) == 0;
165 }
166
167 /* STRING_PIECE_split finds the first occurence of |sep| in |in| and, if found,
168 * sets |*out_left| and |*out_right| to |in| split before and after it. It
169 * returns one if |sep| was found and zero otherwise. */
STRING_PIECE_split(STRING_PIECE * out_left,STRING_PIECE * out_right,const STRING_PIECE * in,char sep)170 static int STRING_PIECE_split(STRING_PIECE *out_left, STRING_PIECE *out_right,
171 const STRING_PIECE *in, char sep) {
172 const char *p = OPENSSL_memchr(in->data, sep, in->len);
173 if (p == NULL) {
174 return 0;
175 }
176 /* |out_left| or |out_right| may alias |in|, so make a copy. */
177 STRING_PIECE in_copy = *in;
178 out_left->data = in_copy.data;
179 out_left->len = p - in_copy.data;
180 out_right->data = in_copy.data + out_left->len + 1;
181 out_right->len = in_copy.len - out_left->len - 1;
182 return 1;
183 }
184
185 /* STRING_PIECE_trim removes leading and trailing whitespace from |s|. */
STRING_PIECE_trim(STRING_PIECE * s)186 static void STRING_PIECE_trim(STRING_PIECE *s) {
187 while (s->len != 0 && (s->data[0] == ' ' || s->data[0] == '\t')) {
188 s->data++;
189 s->len--;
190 }
191 while (s->len != 0 &&
192 (s->data[s->len - 1] == ' ' || s->data[s->len - 1] == '\t')) {
193 s->len--;
194 }
195 }
196
197 /* extract_cpuinfo_field extracts a /proc/cpuinfo field named |field| from
198 * |in|. If found, it sets |*out| to the value and returns one. Otherwise, it
199 * returns zero. */
extract_cpuinfo_field(STRING_PIECE * out,const STRING_PIECE * in,const char * field)200 static int extract_cpuinfo_field(STRING_PIECE *out, const STRING_PIECE *in,
201 const char *field) {
202 /* Process |in| one line at a time. */
203 STRING_PIECE remaining = *in, line;
204 while (STRING_PIECE_split(&line, &remaining, &remaining, '\n')) {
205 STRING_PIECE key, value;
206 if (!STRING_PIECE_split(&key, &value, &line, ':')) {
207 continue;
208 }
209 STRING_PIECE_trim(&key);
210 if (STRING_PIECE_equals(&key, field)) {
211 STRING_PIECE_trim(&value);
212 *out = value;
213 return 1;
214 }
215 }
216
217 return 0;
218 }
219
cpuinfo_field_equals(const STRING_PIECE * cpuinfo,const char * field,const char * value)220 static int cpuinfo_field_equals(const STRING_PIECE *cpuinfo, const char *field,
221 const char *value) {
222 STRING_PIECE extracted;
223 return extract_cpuinfo_field(&extracted, cpuinfo, field) &&
224 STRING_PIECE_equals(&extracted, value);
225 }
226
227 /* has_list_item treats |list| as a space-separated list of items and returns
228 * one if |item| is contained in |list| and zero otherwise. */
has_list_item(const STRING_PIECE * list,const char * item)229 static int has_list_item(const STRING_PIECE *list, const char *item) {
230 STRING_PIECE remaining = *list, feature;
231 while (STRING_PIECE_split(&feature, &remaining, &remaining, ' ')) {
232 if (STRING_PIECE_equals(&feature, item)) {
233 return 1;
234 }
235 }
236 return 0;
237 }
238
get_hwcap_cpuinfo(const STRING_PIECE * cpuinfo)239 static unsigned long get_hwcap_cpuinfo(const STRING_PIECE *cpuinfo) {
240 if (cpuinfo_field_equals(cpuinfo, "CPU architecture", "8")) {
241 /* This is a 32-bit ARM binary running on a 64-bit kernel. NEON is always
242 * available on ARMv8. Linux omits required features, so reading the
243 * "Features" line does not work. (For simplicity, use strict equality. We
244 * assume everything running on future ARM architectures will have a
245 * working |getauxval|.) */
246 return HWCAP_NEON;
247 }
248
249 STRING_PIECE features;
250 if (extract_cpuinfo_field(&features, cpuinfo, "Features") &&
251 has_list_item(&features, "neon")) {
252 return HWCAP_NEON;
253 }
254 return 0;
255 }
256
get_hwcap2_cpuinfo(const STRING_PIECE * cpuinfo)257 static unsigned long get_hwcap2_cpuinfo(const STRING_PIECE *cpuinfo) {
258 STRING_PIECE features;
259 if (!extract_cpuinfo_field(&features, cpuinfo, "Features")) {
260 return 0;
261 }
262
263 unsigned long ret = 0;
264 if (has_list_item(&features, "aes")) {
265 ret |= HWCAP2_AES;
266 }
267 if (has_list_item(&features, "pmull")) {
268 ret |= HWCAP2_PMULL;
269 }
270 if (has_list_item(&features, "sha1")) {
271 ret |= HWCAP2_SHA1;
272 }
273 if (has_list_item(&features, "sha2")) {
274 ret |= HWCAP2_SHA2;
275 }
276 return ret;
277 }
278
279 /* has_broken_neon returns one if |in| matches a CPU known to have a broken
280 * NEON unit. See https://crbug.com/341598. */
has_broken_neon(const STRING_PIECE * cpuinfo)281 static int has_broken_neon(const STRING_PIECE *cpuinfo) {
282 return cpuinfo_field_equals(cpuinfo, "CPU implementer", "0x51") &&
283 cpuinfo_field_equals(cpuinfo, "CPU architecture", "7") &&
284 cpuinfo_field_equals(cpuinfo, "CPU variant", "0x1") &&
285 cpuinfo_field_equals(cpuinfo, "CPU part", "0x04d") &&
286 cpuinfo_field_equals(cpuinfo, "CPU revision", "0");
287 }
288
289 extern uint32_t OPENSSL_armcap_P;
290
291 static int g_has_broken_neon;
292
OPENSSL_cpuid_setup(void)293 void OPENSSL_cpuid_setup(void) {
294 char *cpuinfo_data;
295 size_t cpuinfo_len;
296 if (!read_file(&cpuinfo_data, &cpuinfo_len, "/proc/cpuinfo")) {
297 return;
298 }
299 STRING_PIECE cpuinfo;
300 cpuinfo.data = cpuinfo_data;
301 cpuinfo.len = cpuinfo_len;
302
303 /* |getauxval| is not available on Android until API level 20. If it is
304 * unavailable, read from /proc/self/auxv as a fallback. This is unreadable
305 * on some versions of Android, so further fall back to /proc/cpuinfo.
306 *
307 * See
308 * https://android.googlesource.com/platform/ndk/+/882ac8f3392858991a0e1af33b4b7387ec856bd2
309 * and b/13679666 (Google-internal) for details. */
310 unsigned long hwcap = 0;
311 if (getauxval != NULL) {
312 hwcap = getauxval(AT_HWCAP);
313 }
314 if (hwcap == 0) {
315 hwcap = getauxval_proc(AT_HWCAP);
316 }
317 if (hwcap == 0) {
318 hwcap = get_hwcap_cpuinfo(&cpuinfo);
319 }
320
321 /* Clear NEON support if known broken. */
322 g_has_broken_neon = has_broken_neon(&cpuinfo);
323 if (g_has_broken_neon) {
324 hwcap &= ~HWCAP_NEON;
325 }
326
327 /* Matching OpenSSL, only report other features if NEON is present. */
328 if (hwcap & HWCAP_NEON) {
329 OPENSSL_armcap_P |= ARMV7_NEON;
330
331 /* Some ARMv8 Android devices don't expose AT_HWCAP2. Fall back to
332 * /proc/cpuinfo. See https://crbug.com/596156. */
333 unsigned long hwcap2 = 0;
334 if (getauxval != NULL) {
335 hwcap2 = getauxval(AT_HWCAP2);
336 }
337 if (hwcap2 == 0) {
338 hwcap2 = get_hwcap2_cpuinfo(&cpuinfo);
339 }
340
341 if (hwcap2 & HWCAP2_AES) {
342 OPENSSL_armcap_P |= ARMV8_AES;
343 }
344 if (hwcap2 & HWCAP2_PMULL) {
345 OPENSSL_armcap_P |= ARMV8_PMULL;
346 }
347 if (hwcap2 & HWCAP2_SHA1) {
348 OPENSSL_armcap_P |= ARMV8_SHA1;
349 }
350 if (hwcap2 & HWCAP2_SHA2) {
351 OPENSSL_armcap_P |= ARMV8_SHA256;
352 }
353 }
354
355 OPENSSL_free(cpuinfo_data);
356 }
357
CRYPTO_has_broken_NEON(void)358 int CRYPTO_has_broken_NEON(void) { return g_has_broken_neon; }
359
360 #endif /* OPENSSL_ARM && !OPENSSL_STATIC_ARMCAP */
361