Home | History | Annotate | Download | only in crypto
      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 #include <errno.h>
     19 #include <fcntl.h>
     20 #include <sys/types.h>
     21 #include <unistd.h>
     22 
     23 #include <openssl/arm_arch.h>
     24 #include <openssl/buf.h>
     25 #include <openssl/mem.h>
     26 
     27 #include "cpu-arm-linux.h"
     28 
     29 #define AT_HWCAP 16
     30 #define AT_HWCAP2 26
     31 
     32 // |getauxval| is not available on Android until API level 20. Link it as a weak
     33 // symbol and use other methods as fallback.
     34 unsigned long getauxval(unsigned long type) __attribute__((weak));
     35 
     36 static int open_eintr(const char *path, int flags) {
     37   int ret;
     38   do {
     39     ret = open(path, flags);
     40   } while (ret < 0 && errno == EINTR);
     41   return ret;
     42 }
     43 
     44 static ssize_t read_eintr(int fd, void *out, size_t len) {
     45   ssize_t ret;
     46   do {
     47     ret = read(fd, out, len);
     48   } while (ret < 0 && errno == EINTR);
     49   return ret;
     50 }
     51 
     52 // read_full reads exactly |len| bytes from |fd| to |out|. On error or end of
     53 // file, it returns zero.
     54 static int read_full(int fd, void *out, size_t len) {
     55   char *outp = out;
     56   while (len > 0) {
     57     ssize_t ret = read_eintr(fd, outp, len);
     58     if (ret <= 0) {
     59       return 0;
     60     }
     61     outp += ret;
     62     len -= ret;
     63   }
     64   return 1;
     65 }
     66 
     67 // read_file opens |path| and reads until end-of-file. On success, it returns
     68 // one and sets |*out_ptr| and |*out_len| to a newly-allocated buffer with the
     69 // contents. Otherwise, it returns zero.
     70 static int read_file(char **out_ptr, size_t *out_len, const char *path) {
     71   int fd = open_eintr(path, O_RDONLY);
     72   if (fd < 0) {
     73     return 0;
     74   }
     75 
     76   static const size_t kReadSize = 1024;
     77   int ret = 0;
     78   size_t cap = kReadSize, len = 0;
     79   char *buf = OPENSSL_malloc(cap);
     80   if (buf == NULL) {
     81     goto err;
     82   }
     83 
     84   for (;;) {
     85     if (cap - len < kReadSize) {
     86       size_t new_cap = cap * 2;
     87       if (new_cap < cap) {
     88         goto err;
     89       }
     90       char *new_buf = OPENSSL_realloc(buf, new_cap);
     91       if (new_buf == NULL) {
     92         goto err;
     93       }
     94       buf = new_buf;
     95       cap = new_cap;
     96     }
     97 
     98     ssize_t bytes_read = read_eintr(fd, buf + len, kReadSize);
     99     if (bytes_read < 0) {
    100       goto err;
    101     }
    102     if (bytes_read == 0) {
    103       break;
    104     }
    105     len += bytes_read;
    106   }
    107 
    108   *out_ptr = buf;
    109   *out_len = len;
    110   ret = 1;
    111   buf = NULL;
    112 
    113 err:
    114   OPENSSL_free(buf);
    115   close(fd);
    116   return ret;
    117 }
    118 
    119 // getauxval_proc behaves like |getauxval| but reads from /proc/self/auxv.
    120 static unsigned long getauxval_proc(unsigned long type) {
    121   int fd = open_eintr("/proc/self/auxv", O_RDONLY);
    122   if (fd < 0) {
    123     return 0;
    124   }
    125 
    126   struct {
    127     unsigned long tag;
    128     unsigned long value;
    129   } entry;
    130 
    131   for (;;) {
    132     if (!read_full(fd, &entry, sizeof(entry)) ||
    133         (entry.tag == 0 && entry.value == 0)) {
    134       break;
    135     }
    136     if (entry.tag == type) {
    137       close(fd);
    138       return entry.value;
    139     }
    140   }
    141   close(fd);
    142   return 0;
    143 }
    144 
    145 extern uint32_t OPENSSL_armcap_P;
    146 
    147 static int g_has_broken_neon, g_needs_hwcap2_workaround;
    148 
    149 void OPENSSL_cpuid_setup(void) {
    150   char *cpuinfo_data;
    151   size_t cpuinfo_len;
    152   if (!read_file(&cpuinfo_data, &cpuinfo_len, "/proc/cpuinfo")) {
    153     return;
    154   }
    155   STRING_PIECE cpuinfo;
    156   cpuinfo.data = cpuinfo_data;
    157   cpuinfo.len = cpuinfo_len;
    158 
    159   // |getauxval| is not available on Android until API level 20. If it is
    160   // unavailable, read from /proc/self/auxv as a fallback. This is unreadable
    161   // on some versions of Android, so further fall back to /proc/cpuinfo.
    162   //
    163   // See
    164   // https://android.googlesource.com/platform/ndk/+/882ac8f3392858991a0e1af33b4b7387ec856bd2
    165   // and b/13679666 (Google-internal) for details.
    166   unsigned long hwcap = 0;
    167   if (getauxval != NULL) {
    168     hwcap = getauxval(AT_HWCAP);
    169   }
    170   if (hwcap == 0) {
    171     hwcap = getauxval_proc(AT_HWCAP);
    172   }
    173   if (hwcap == 0) {
    174     hwcap = crypto_get_arm_hwcap_from_cpuinfo(&cpuinfo);
    175   }
    176 
    177   // Clear NEON support if known broken.
    178   g_has_broken_neon = crypto_cpuinfo_has_broken_neon(&cpuinfo);
    179   if (g_has_broken_neon) {
    180     hwcap &= ~HWCAP_NEON;
    181   }
    182 
    183   // Matching OpenSSL, only report other features if NEON is present.
    184   if (hwcap & HWCAP_NEON) {
    185     OPENSSL_armcap_P |= ARMV7_NEON;
    186 
    187     // Some ARMv8 Android devices don't expose AT_HWCAP2. Fall back to
    188     // /proc/cpuinfo. See https://crbug.com/596156.
    189     unsigned long hwcap2 = 0;
    190     if (getauxval != NULL) {
    191       hwcap2 = getauxval(AT_HWCAP2);
    192     }
    193     if (hwcap2 == 0) {
    194       hwcap2 = crypto_get_arm_hwcap2_from_cpuinfo(&cpuinfo);
    195       g_needs_hwcap2_workaround = hwcap2 != 0;
    196     }
    197 
    198     if (hwcap2 & HWCAP2_AES) {
    199       OPENSSL_armcap_P |= ARMV8_AES;
    200     }
    201     if (hwcap2 & HWCAP2_PMULL) {
    202       OPENSSL_armcap_P |= ARMV8_PMULL;
    203     }
    204     if (hwcap2 & HWCAP2_SHA1) {
    205       OPENSSL_armcap_P |= ARMV8_SHA1;
    206     }
    207     if (hwcap2 & HWCAP2_SHA2) {
    208       OPENSSL_armcap_P |= ARMV8_SHA256;
    209     }
    210   }
    211 
    212   OPENSSL_free(cpuinfo_data);
    213 }
    214 
    215 int CRYPTO_has_broken_NEON(void) { return g_has_broken_neon; }
    216 
    217 int CRYPTO_needs_hwcap2_workaround(void) { return g_needs_hwcap2_workaround; }
    218 
    219 #endif  // OPENSSL_ARM && !OPENSSL_STATIC_ARMCAP
    220