aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crypto/CMakeLists.txt1
-rw-r--r--crypto/cpu-arm-linux.c294
-rw-r--r--crypto/cpu-arm-linux.h59
-rw-r--r--crypto/cpu-arm-linux_test.cc236
-rw-r--r--fuzz/CMakeLists.txt1
-rw-r--r--fuzz/arm_cpuinfo.cc24
-rw-r--r--fuzz/arm_cpuinfo_corpus/0b628cc4b99b6b797a0486c67a6ff6fa7d24b3b417
-rw-r--r--fuzz/arm_cpuinfo_corpus/27cdc19e630f4174c00376cdc51b1c556723b0e114
-rw-r--r--fuzz/arm_cpuinfo_corpus/8e90793faafbdfa30081e963e45fff08a360dc7514
-rw-r--r--fuzz/arm_cpuinfo_corpus/d8895d2c91f858239b2670eb211af78a71d75d0274
-rw-r--r--fuzz/arm_cpuinfo_corpus/dfa633d05f10f2cb5c32b0a767efd10bf36cf3be23
11 files changed, 613 insertions, 144 deletions
diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt
index 2684750..5aab4af 100644
--- a/crypto/CMakeLists.txt
+++ b/crypto/CMakeLists.txt
@@ -237,6 +237,7 @@ add_executable(
cmac/cmac_test.cc
compiler_test.cc
constant_time_test.cc
+ cpu-arm-linux_test.cc
curve25519/ed25519_test.cc
curve25519/spake25519_test.cc
curve25519/x25519_test.cc
diff --git a/crypto/cpu-arm-linux.c b/crypto/cpu-arm-linux.c
index 839b632..91078bd 100644
--- a/crypto/cpu-arm-linux.c
+++ b/crypto/cpu-arm-linux.c
@@ -14,150 +14,23 @@
#include <openssl/cpu.h>
-#if defined(OPENSSL_ARM) && !defined(OPENSSL_STATIC_ARMCAP)
+#include "cpu-arm-linux.h"
+#include "internal.h"
+#if defined(OPENSSL_ARM) && !defined(OPENSSL_STATIC_ARMCAP)
#include <errno.h>
#include <fcntl.h>
-#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <openssl/arm_arch.h>
#include <openssl/buf.h>
#include <openssl/mem.h>
+#endif
-#include "internal.h"
-
-
-#define AT_HWCAP 16
-#define AT_HWCAP2 26
-
-#define HWCAP_NEON (1 << 12)
-
-// See /usr/include/asm/hwcap.h on an ARM installation for the source of
-// these values.
-#define HWCAP2_AES (1 << 0)
-#define HWCAP2_PMULL (1 << 1)
-#define HWCAP2_SHA1 (1 << 2)
-#define HWCAP2_SHA2 (1 << 3)
-
-// |getauxval| is not available on Android until API level 20. Link it as a weak
-// symbol and use other methods as fallback.
-unsigned long getauxval(unsigned long type) __attribute__((weak));
-
-static int open_eintr(const char *path, int flags) {
- int ret;
- do {
- ret = open(path, flags);
- } while (ret < 0 && errno == EINTR);
- return ret;
-}
-
-static ssize_t read_eintr(int fd, void *out, size_t len) {
- ssize_t ret;
- do {
- ret = read(fd, out, len);
- } while (ret < 0 && errno == EINTR);
- return ret;
-}
-
-// read_full reads exactly |len| bytes from |fd| to |out|. On error or end of
-// file, it returns zero.
-static int read_full(int fd, void *out, size_t len) {
- char *outp = out;
- while (len > 0) {
- ssize_t ret = read_eintr(fd, outp, len);
- if (ret <= 0) {
- return 0;
- }
- outp += ret;
- len -= ret;
- }
- return 1;
-}
-
-// read_file opens |path| and reads until end-of-file. On success, it returns
-// one and sets |*out_ptr| and |*out_len| to a newly-allocated buffer with the
-// contents. Otherwise, it returns zero.
-static int read_file(char **out_ptr, size_t *out_len, const char *path) {
- int fd = open_eintr(path, O_RDONLY);
- if (fd < 0) {
- return 0;
- }
-
- static const size_t kReadSize = 1024;
- int ret = 0;
- size_t cap = kReadSize, len = 0;
- char *buf = OPENSSL_malloc(cap);
- if (buf == NULL) {
- goto err;
- }
-
- for (;;) {
- if (cap - len < kReadSize) {
- size_t new_cap = cap * 2;
- if (new_cap < cap) {
- goto err;
- }
- char *new_buf = OPENSSL_realloc(buf, new_cap);
- if (new_buf == NULL) {
- goto err;
- }
- buf = new_buf;
- cap = new_cap;
- }
-
- ssize_t bytes_read = read_eintr(fd, buf + len, kReadSize);
- if (bytes_read < 0) {
- goto err;
- }
- if (bytes_read == 0) {
- break;
- }
- len += bytes_read;
- }
-
- *out_ptr = buf;
- *out_len = len;
- ret = 1;
- buf = NULL;
-
-err:
- OPENSSL_free(buf);
- close(fd);
- return ret;
-}
-
-// getauxval_proc behaves like |getauxval| but reads from /proc/self/auxv.
-static unsigned long getauxval_proc(unsigned long type) {
- int fd = open_eintr("/proc/self/auxv", O_RDONLY);
- if (fd < 0) {
- return 0;
- }
- struct {
- unsigned long tag;
- unsigned long value;
- } entry;
-
- for (;;) {
- if (!read_full(fd, &entry, sizeof(entry)) ||
- (entry.tag == 0 && entry.value == 0)) {
- break;
- }
- if (entry.tag == type) {
- close(fd);
- return entry.value;
- }
- }
- close(fd);
- return 0;
-}
-
-typedef struct {
- const char *data;
- size_t len;
-} STRING_PIECE;
+// The following functions are only used in ARM, but they are defined on all
+// platforms for testing and fuzzing purposes.
static int STRING_PIECE_equals(const STRING_PIECE *a, const char *b) {
size_t b_len = strlen(b);
@@ -182,6 +55,23 @@ static int STRING_PIECE_split(STRING_PIECE *out_left, STRING_PIECE *out_right,
return 1;
}
+// STRING_PIECE_get_delimited reads a |sep|-delimited entry from |s|, writing it
+// to |out| and updating |s| to point beyond it. It returns one on success and
+// zero if |s| is empty. If |s| is has no copies of |sep| and is non-empty, it
+// reads the entire string to |out|.
+static int STRING_PIECE_get_delimited(STRING_PIECE *s, STRING_PIECE *out, char sep) {
+ if (s->len == 0) {
+ return 0;
+ }
+ if (!STRING_PIECE_split(out, s, s, sep)) {
+ // |s| had no instances of |sep|. Return the entire string.
+ *out = *s;
+ s->data += s->len;
+ s->len = 0;
+ }
+ return 1;
+}
+
// STRING_PIECE_trim removes leading and trailing whitespace from |s|.
static void STRING_PIECE_trim(STRING_PIECE *s) {
while (s->len != 0 && (s->data[0] == ' ' || s->data[0] == '\t')) {
@@ -195,13 +85,13 @@ static void STRING_PIECE_trim(STRING_PIECE *s) {
}
// extract_cpuinfo_field extracts a /proc/cpuinfo field named |field| from
-// |in|. If found, it sets |*out| to the value and returns one. Otherwise, it
+// |in|. If found, it sets |*out| to the value and returns one. Otherwise, it
// returns zero.
static int extract_cpuinfo_field(STRING_PIECE *out, const STRING_PIECE *in,
const char *field) {
// Process |in| one line at a time.
STRING_PIECE remaining = *in, line;
- while (STRING_PIECE_split(&line, &remaining, &remaining, '\n')) {
+ while (STRING_PIECE_get_delimited(&remaining, &line, '\n')) {
STRING_PIECE key, value;
if (!STRING_PIECE_split(&key, &value, &line, ':')) {
continue;
@@ -228,7 +118,7 @@ static int cpuinfo_field_equals(const STRING_PIECE *cpuinfo, const char *field,
// one if |item| is contained in |list| and zero otherwise.
static int has_list_item(const STRING_PIECE *list, const char *item) {
STRING_PIECE remaining = *list, feature;
- while (STRING_PIECE_split(&feature, &remaining, &remaining, ' ')) {
+ while (STRING_PIECE_get_delimited(&remaining, &feature, ' ')) {
if (STRING_PIECE_equals(&feature, item)) {
return 1;
}
@@ -236,7 +126,7 @@ static int has_list_item(const STRING_PIECE *list, const char *item) {
return 0;
}
-static unsigned long get_hwcap_cpuinfo(const STRING_PIECE *cpuinfo) {
+unsigned long crypto_get_arm_hwcap_from_cpuinfo(const STRING_PIECE *cpuinfo) {
if (cpuinfo_field_equals(cpuinfo, "CPU architecture", "8")) {
// This is a 32-bit ARM binary running on a 64-bit kernel. NEON is always
// available on ARMv8. Linux omits required features, so reading the
@@ -254,7 +144,7 @@ static unsigned long get_hwcap_cpuinfo(const STRING_PIECE *cpuinfo) {
return 0;
}
-static unsigned long get_hwcap2_cpuinfo(const STRING_PIECE *cpuinfo) {
+unsigned long crypto_get_arm_hwcap2_from_cpuinfo(const STRING_PIECE *cpuinfo) {
STRING_PIECE features;
if (!extract_cpuinfo_field(&features, cpuinfo, "Features")) {
return 0;
@@ -276,9 +166,7 @@ static unsigned long get_hwcap2_cpuinfo(const STRING_PIECE *cpuinfo) {
return ret;
}
-// has_broken_neon returns one if |in| matches a CPU known to have a broken
-// NEON unit. See https://crbug.com/341598.
-static int has_broken_neon(const STRING_PIECE *cpuinfo) {
+int crypto_cpuinfo_has_broken_neon(const STRING_PIECE *cpuinfo) {
return cpuinfo_field_equals(cpuinfo, "CPU implementer", "0x51") &&
cpuinfo_field_equals(cpuinfo, "CPU architecture", "7") &&
cpuinfo_field_equals(cpuinfo, "CPU variant", "0x1") &&
@@ -286,6 +174,124 @@ static int has_broken_neon(const STRING_PIECE *cpuinfo) {
cpuinfo_field_equals(cpuinfo, "CPU revision", "0");
}
+#if defined(OPENSSL_ARM) && !defined(OPENSSL_STATIC_ARMCAP)
+
+#define AT_HWCAP 16
+#define AT_HWCAP2 26
+
+// |getauxval| is not available on Android until API level 20. Link it as a weak
+// symbol and use other methods as fallback.
+unsigned long getauxval(unsigned long type) __attribute__((weak));
+
+static int open_eintr(const char *path, int flags) {
+ int ret;
+ do {
+ ret = open(path, flags);
+ } while (ret < 0 && errno == EINTR);
+ return ret;
+}
+
+static ssize_t read_eintr(int fd, void *out, size_t len) {
+ ssize_t ret;
+ do {
+ ret = read(fd, out, len);
+ } while (ret < 0 && errno == EINTR);
+ return ret;
+}
+
+// read_full reads exactly |len| bytes from |fd| to |out|. On error or end of
+// file, it returns zero.
+static int read_full(int fd, void *out, size_t len) {
+ char *outp = out;
+ while (len > 0) {
+ ssize_t ret = read_eintr(fd, outp, len);
+ if (ret <= 0) {
+ return 0;
+ }
+ outp += ret;
+ len -= ret;
+ }
+ return 1;
+}
+
+// read_file opens |path| and reads until end-of-file. On success, it returns
+// one and sets |*out_ptr| and |*out_len| to a newly-allocated buffer with the
+// contents. Otherwise, it returns zero.
+static int read_file(char **out_ptr, size_t *out_len, const char *path) {
+ int fd = open_eintr(path, O_RDONLY);
+ if (fd < 0) {
+ return 0;
+ }
+
+ static const size_t kReadSize = 1024;
+ int ret = 0;
+ size_t cap = kReadSize, len = 0;
+ char *buf = OPENSSL_malloc(cap);
+ if (buf == NULL) {
+ goto err;
+ }
+
+ for (;;) {
+ if (cap - len < kReadSize) {
+ size_t new_cap = cap * 2;
+ if (new_cap < cap) {
+ goto err;
+ }
+ char *new_buf = OPENSSL_realloc(buf, new_cap);
+ if (new_buf == NULL) {
+ goto err;
+ }
+ buf = new_buf;
+ cap = new_cap;
+ }
+
+ ssize_t bytes_read = read_eintr(fd, buf + len, kReadSize);
+ if (bytes_read < 0) {
+ goto err;
+ }
+ if (bytes_read == 0) {
+ break;
+ }
+ len += bytes_read;
+ }
+
+ *out_ptr = buf;
+ *out_len = len;
+ ret = 1;
+ buf = NULL;
+
+err:
+ OPENSSL_free(buf);
+ close(fd);
+ return ret;
+}
+
+// getauxval_proc behaves like |getauxval| but reads from /proc/self/auxv.
+static unsigned long getauxval_proc(unsigned long type) {
+ int fd = open_eintr("/proc/self/auxv", O_RDONLY);
+ if (fd < 0) {
+ return 0;
+ }
+
+ struct {
+ unsigned long tag;
+ unsigned long value;
+ } entry;
+
+ for (;;) {
+ if (!read_full(fd, &entry, sizeof(entry)) ||
+ (entry.tag == 0 && entry.value == 0)) {
+ break;
+ }
+ if (entry.tag == type) {
+ close(fd);
+ return entry.value;
+ }
+ }
+ close(fd);
+ return 0;
+}
+
extern uint32_t OPENSSL_armcap_P;
static int g_has_broken_neon, g_needs_hwcap2_workaround;
@@ -315,11 +321,11 @@ void OPENSSL_cpuid_setup(void) {
hwcap = getauxval_proc(AT_HWCAP);
}
if (hwcap == 0) {
- hwcap = get_hwcap_cpuinfo(&cpuinfo);
+ hwcap = crypto_get_arm_hwcap_from_cpuinfo(&cpuinfo);
}
// Clear NEON support if known broken.
- g_has_broken_neon = has_broken_neon(&cpuinfo);
+ g_has_broken_neon = crypto_cpuinfo_has_broken_neon(&cpuinfo);
if (g_has_broken_neon) {
hwcap &= ~HWCAP_NEON;
}
@@ -335,7 +341,7 @@ void OPENSSL_cpuid_setup(void) {
hwcap2 = getauxval(AT_HWCAP2);
}
if (hwcap2 == 0) {
- hwcap2 = get_hwcap2_cpuinfo(&cpuinfo);
+ hwcap2 = crypto_get_arm_hwcap2_from_cpuinfo(&cpuinfo);
g_needs_hwcap2_workaround = hwcap2 != 0;
}
diff --git a/crypto/cpu-arm-linux.h b/crypto/cpu-arm-linux.h
new file mode 100644
index 0000000..eabf4ea
--- /dev/null
+++ b/crypto/cpu-arm-linux.h
@@ -0,0 +1,59 @@
+/* Copyright (c) 2018, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#ifndef OPENSSL_HEADER_CRYPTO_CPU_ARM_LINUX_H
+#define OPENSSL_HEADER_CRYPTO_CPU_ARM_LINUX_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+// The following symbols are defined on all platforms and exported for testing
+// and fuzzing purposes. They are not exported from the shared library so the
+// static linker will drop them outside of tests.
+
+#define HWCAP_NEON (1 << 12)
+
+// See /usr/include/asm/hwcap.h on an ARM installation for the source of
+// these values.
+#define HWCAP2_AES (1 << 0)
+#define HWCAP2_PMULL (1 << 1)
+#define HWCAP2_SHA1 (1 << 2)
+#define HWCAP2_SHA2 (1 << 3)
+
+typedef struct {
+ const char *data;
+ size_t len;
+} STRING_PIECE;
+
+// crypto_get_arm_hwcap_from_cpuinfo returns an equivalent ARM |AT_HWCAP| value
+// from |cpuinfo|.
+unsigned long crypto_get_arm_hwcap_from_cpuinfo(const STRING_PIECE *cpuinfo);
+
+// crypto_get_arm_hwcap2_from_cpuinfo returns an equivalent ARM |AT_HWCAP2|
+// value from |cpuinfo|.
+unsigned long crypto_get_arm_hwcap2_from_cpuinfo(const STRING_PIECE *cpuinfo);
+
+// crypto_cpuinfo_has_broken_neon returns one if |cpuinfo| matches a CPU known
+// to have broken NEON unit and zero otherwise. See https://crbug.com/341598.
+int crypto_cpuinfo_has_broken_neon(const STRING_PIECE *cpuinfo);
+
+#if defined(__cplusplus)
+} // extern C
+#endif
+
+#endif // OPENSSL_HEADER_CRYPTO_CPU_ARM_LINUX_H
diff --git a/crypto/cpu-arm-linux_test.cc b/crypto/cpu-arm-linux_test.cc
new file mode 100644
index 0000000..056aa80
--- /dev/null
+++ b/crypto/cpu-arm-linux_test.cc
@@ -0,0 +1,236 @@
+/* Copyright (c) 2018, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include "cpu-arm-linux.h"
+
+#include <string.h>
+
+#include <gtest/gtest.h>
+
+
+#if !defined(BORINGSSL_SHARED_LIBRARY)
+
+TEST(ARMLinuxTest, CPUInfo) {
+ struct Test {
+ const char *cpuinfo;
+ unsigned long hwcap;
+ unsigned long hwcap2;
+ bool broken_neon;
+ } kTests[] = {
+ // https://crbug.com/341598#c33
+ {
+ "Processor: ARMv7 Processory rev 0 (v71)\n"
+ "processor: 0\n"
+ "BogoMIPS: 13.50\n"
+ "\n"
+ "Processor: 1\n"
+ "BogoMIPS: 13.50\n"
+ "\n"
+ "Features: swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 "
+ "idiva idivt\n"
+ "CPU implementer : 0x51\n"
+ "CPU architecture: 7\n"
+ "CPU variant: 0x1\n"
+ "CPU part: 0x04d\n"
+ "CPU revision: 0\n"
+ "\n"
+ "Hardware: SAMSUNG M2\n"
+ "Revision: 0010\n"
+ "Serial: 00001e030000354e\n",
+ HWCAP_NEON,
+ 0,
+ true,
+ },
+ // https://crbug.com/341598#c39
+ {
+ "Processor : ARMv7 Processor rev 0 (v7l)\n"
+ "processor : 0\n"
+ "BogoMIPS : 13.53\n"
+ "\n"
+ "Features : swp half thumb fastmult vfp edsp neon vfpv3 tls "
+ "vfpv4\n"
+ "CPU implementer : 0x51\n"
+ "CPU architecture: 7\n"
+ "CPU variant : 0x1\n"
+ "CPU part : 0x04d\n"
+ "CPU revision : 0\n"
+ "\n"
+ "Hardware : SAMSUNG M2_ATT\n"
+ "Revision : 0010\n"
+ "Serial : 0000df0c00004d4c\n",
+ HWCAP_NEON,
+ 0,
+ true,
+ },
+ // Nexus 4 from https://crbug.com/341598#c43
+ {
+ "Processor : ARMv7 Processor rev 2 (v7l)\n"
+ "processor : 0\n"
+ "BogoMIPS : 13.53\n"
+ "\n"
+ "processor : 1\n"
+ "BogoMIPS : 13.53\n"
+ "\n"
+ "processor : 2\n"
+ "BogoMIPS : 13.53\n"
+ "\n"
+ "processor : 3\n"
+ "BogoMIPS : 13.53\n"
+ "\n"
+ "Features : swp half thumb fastmult vfp edsp neon vfpv3 tls "
+ "vfpv4 \n"
+ "CPU implementer : 0x51\n"
+ "CPU architecture: 7\n"
+ "CPU variant : 0x0\n"
+ "CPU part : 0x06f\n"
+ "CPU revision : 2\n"
+ "\n"
+ "Hardware : QCT APQ8064 MAKO\n"
+ "Revision : 000b\n"
+ "Serial : 0000000000000000\n",
+ HWCAP_NEON,
+ 0,
+ false,
+ },
+ // Razr M from https://crbug.com/341598#c43
+ {
+ "Processor : ARMv7 Processor rev 4 (v7l)\n"
+ "processor : 0\n"
+ "BogoMIPS : 13.53\n"
+ "\n"
+ "Features : swp half thumb fastmult vfp edsp neon vfpv3 tls "
+ "vfpv4\n"
+ "CPU implementer : 0x51\n"
+ "CPU architecture: 7\n"
+ "CPU variant : 0x1\n"
+ "CPU part : 0x04d\n"
+ "CPU revision : 4\n"
+ "\n"
+ "Hardware : msm8960dt\n"
+ "Revision : 82a0\n"
+ "Serial : 0001000201fe37a5\n",
+ HWCAP_NEON,
+ 0,
+ false,
+ },
+ // Pixel 2 (truncated slightly)
+ {
+ "Processor : AArch64 Processor rev 1 (aarch64)\n"
+ "processor : 0\n"
+ "BogoMIPS : 38.00\n"
+ "Features : fp asimd evtstrm aes pmull sha1 sha2 crc32\n"
+ "CPU implementer : 0x51\n"
+ "CPU architecture: 8\n"
+ "CPU variant : 0xa\n"
+ "CPU part : 0x801\n"
+ "CPU revision : 4\n"
+ "\n"
+ "processor : 1\n"
+ "BogoMIPS : 38.00\n"
+ "Features : fp asimd evtstrm aes pmull sha1 sha2 crc32\n"
+ "CPU implementer : 0x51\n"
+ "CPU architecture: 8\n"
+ "CPU variant : 0xa\n"
+ "CPU part : 0x801\n"
+ "CPU revision : 4\n"
+ "\n"
+ "processor : 2\n"
+ "BogoMIPS : 38.00\n"
+ "Features : fp asimd evtstrm aes pmull sha1 sha2 crc32\n"
+ "CPU implementer : 0x51\n"
+ "CPU architecture: 8\n"
+ "CPU variant : 0xa\n"
+ "CPU part : 0x801\n"
+ "CPU revision : 4\n"
+ "\n"
+ "processor : 3\n"
+ "BogoMIPS : 38.00\n"
+ "Features : fp asimd evtstrm aes pmull sha1 sha2 crc32\n"
+ "CPU implementer : 0x51\n"
+ "CPU architecture: 8\n"
+ "CPU variant : 0xa\n"
+ "CPU part : 0x801\n"
+ "CPU revision : 4\n"
+ // (Extra processors omitted.)
+ "\n"
+ "Hardware : Qualcomm Technologies, Inc MSM8998\n",
+ HWCAP_NEON, // CPU architecture 8 implies NEON.
+ HWCAP2_AES | HWCAP2_PMULL | HWCAP2_SHA1 | HWCAP2_SHA2,
+ false,
+ },
+ // Nexus 4 from
+ // Garbage should be tolerated.
+ {
+ "Blah blah blah this is definitely an ARM CPU",
+ 0,
+ 0,
+ false,
+ },
+ // A hypothetical ARMv8 CPU without crc32 (and thus no trailing space
+ // after the last crypto entry).
+ {
+ "Features : aes pmull sha1 sha2\n"
+ "CPU architecture: 8\n",
+ HWCAP_NEON,
+ HWCAP2_AES | HWCAP2_PMULL | HWCAP2_SHA1 | HWCAP2_SHA2,
+ false,
+ },
+ // Various combinations of ARMv8 flags.
+ {
+ "Features : aes sha1 sha2\n"
+ "CPU architecture: 8\n",
+ HWCAP_NEON,
+ HWCAP2_AES | HWCAP2_SHA1 | HWCAP2_SHA2,
+ false,
+ },
+ {
+ "Features : pmull sha2\n"
+ "CPU architecture: 8\n",
+ HWCAP_NEON,
+ HWCAP2_PMULL | HWCAP2_SHA2,
+ false,
+ },
+ {
+ "Features : aes aes aes not_aes aes aes \n"
+ "CPU architecture: 8\n",
+ HWCAP_NEON,
+ HWCAP2_AES,
+ false,
+ },
+ {
+ "Features : \n"
+ "CPU architecture: 8\n",
+ HWCAP_NEON,
+ 0,
+ false,
+ },
+ {
+ "Features : nothing\n"
+ "CPU architecture: 8\n",
+ HWCAP_NEON,
+ 0,
+ false,
+ },
+ };
+
+ for (const auto &t : kTests) {
+ SCOPED_TRACE(t.cpuinfo);
+ STRING_PIECE sp = {t.cpuinfo, strlen(t.cpuinfo)};
+ EXPECT_EQ(t.hwcap, crypto_get_arm_hwcap_from_cpuinfo(&sp));
+ EXPECT_EQ(t.hwcap2, crypto_get_arm_hwcap2_from_cpuinfo(&sp));
+ EXPECT_EQ(t.broken_neon ? 1 : 0, crypto_cpuinfo_has_broken_neon(&sp));
+ }
+}
+
+#endif // !BORINGSSL_SHARED_LIBRARY
diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt
index b7dbd6b..f60dc00 100644
--- a/fuzz/CMakeLists.txt
+++ b/fuzz/CMakeLists.txt
@@ -8,6 +8,7 @@ macro(fuzzer name)
set_target_properties(${name} PROPERTIES LINK_FLAGS "-fsanitize=fuzzer")
endmacro()
+fuzzer(arm_cpuinfo)
fuzzer(bn_mod_exp)
fuzzer(privkey)
fuzzer(cert)
diff --git a/fuzz/arm_cpuinfo.cc b/fuzz/arm_cpuinfo.cc
new file mode 100644
index 0000000..5d70046
--- /dev/null
+++ b/fuzz/arm_cpuinfo.cc
@@ -0,0 +1,24 @@
+/* Copyright (c) 2018, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include "../crypto/cpu-arm-linux.h"
+
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
+ STRING_PIECE sp = {reinterpret_cast<const char *>(buf), len};
+ crypto_get_arm_hwcap_from_cpuinfo(&sp);
+ crypto_get_arm_hwcap2_from_cpuinfo(&sp);
+ crypto_cpuinfo_has_broken_neon(&sp);
+ return 0;
+}
diff --git a/fuzz/arm_cpuinfo_corpus/0b628cc4b99b6b797a0486c67a6ff6fa7d24b3b4 b/fuzz/arm_cpuinfo_corpus/0b628cc4b99b6b797a0486c67a6ff6fa7d24b3b4
new file mode 100644
index 0000000..c95dfd3
--- /dev/null
+++ b/fuzz/arm_cpuinfo_corpus/0b628cc4b99b6b797a0486c67a6ff6fa7d24b3b4
@@ -0,0 +1,17 @@
+Processor: ARMv7 Processory rev 0 (v71)
+processor: 0
+BogoMIPS: 13.50
+
+Processor: 1
+BogoMIPS: 13.50
+
+Features: swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt
+CPU implementer : 0x51
+CPU architecture: 7
+CPU variant: 0x1
+CPU part: 0x04d
+CPU revision: 0
+
+Hardware: SAMSUNG M2
+Revision: 0010
+Serial: 00001e030000354e
diff --git a/fuzz/arm_cpuinfo_corpus/27cdc19e630f4174c00376cdc51b1c556723b0e1 b/fuzz/arm_cpuinfo_corpus/27cdc19e630f4174c00376cdc51b1c556723b0e1
new file mode 100644
index 0000000..89b9a0c
--- /dev/null
+++ b/fuzz/arm_cpuinfo_corpus/27cdc19e630f4174c00376cdc51b1c556723b0e1
@@ -0,0 +1,14 @@
+Processor : ARMv7 Processor rev 0 (v7l)
+processor : 0
+BogoMIPS : 13.53
+
+Features : swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4
+CPU implementer : 0x51
+CPU architecture: 7
+CPU variant : 0x1
+CPU part : 0x04d
+CPU revision : 0
+
+Hardware : SAMSUNG M2_ATT
+Revision : 0010
+Serial : 0000df0c00004d4c
diff --git a/fuzz/arm_cpuinfo_corpus/8e90793faafbdfa30081e963e45fff08a360dc75 b/fuzz/arm_cpuinfo_corpus/8e90793faafbdfa30081e963e45fff08a360dc75
new file mode 100644
index 0000000..4709eb2
--- /dev/null
+++ b/fuzz/arm_cpuinfo_corpus/8e90793faafbdfa30081e963e45fff08a360dc75
@@ -0,0 +1,14 @@
+Processor : ARMv7 Processor rev 4 (v7l)
+processor : 0
+BogoMIPS : 13.53
+
+Features : swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4
+CPU implementer : 0x51
+CPU architecture: 7
+CPU variant : 0x1
+CPU part : 0x04d
+CPU revision : 4
+
+Hardware : msm8960dt
+Revision : 82a0
+Serial : 0001000201fe37a5
diff --git a/fuzz/arm_cpuinfo_corpus/d8895d2c91f858239b2670eb211af78a71d75d02 b/fuzz/arm_cpuinfo_corpus/d8895d2c91f858239b2670eb211af78a71d75d02
new file mode 100644
index 0000000..60a5409
--- /dev/null
+++ b/fuzz/arm_cpuinfo_corpus/d8895d2c91f858239b2670eb211af78a71d75d02
@@ -0,0 +1,74 @@
+Processor : AArch64 Processor rev 1 (aarch64)
+processor : 0
+BogoMIPS : 38.00
+Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
+CPU implementer : 0x51
+CPU architecture: 8
+CPU variant : 0xa
+CPU part : 0x801
+CPU revision : 4
+
+processor : 1
+BogoMIPS : 38.00
+Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
+CPU implementer : 0x51
+CPU architecture: 8
+CPU variant : 0xa
+CPU part : 0x801
+CPU revision : 4
+
+processor : 2
+BogoMIPS : 38.00
+Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
+CPU implementer : 0x51
+CPU architecture: 8
+CPU variant : 0xa
+CPU part : 0x801
+CPU revision : 4
+
+processor : 3
+BogoMIPS : 38.00
+Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
+CPU implementer : 0x51
+CPU architecture: 8
+CPU variant : 0xa
+CPU part : 0x801
+CPU revision : 4
+
+processor : 4
+BogoMIPS : 38.00
+Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
+CPU implementer : 0x51
+CPU architecture: 8
+CPU variant : 0xa
+CPU part : 0x800
+CPU revision : 1
+
+processor : 5
+BogoMIPS : 38.00
+Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
+CPU implementer : 0x51
+CPU architecture: 8
+CPU variant : 0xa
+CPU part : 0x800
+CPU revision : 1
+
+processor : 6
+BogoMIPS : 38.00
+Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
+CPU implementer : 0x51
+CPU architecture: 8
+CPU variant : 0xa
+CPU part : 0x800
+CPU revision : 1
+
+processor : 7
+BogoMIPS : 38.00
+Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
+CPU implementer : 0x51
+CPU architecture: 8
+CPU variant : 0xa
+CPU part : 0x800
+CPU revision : 1
+
+Hardware : Qualcomm Technologies, Inc MSM8998
diff --git a/fuzz/arm_cpuinfo_corpus/dfa633d05f10f2cb5c32b0a767efd10bf36cf3be b/fuzz/arm_cpuinfo_corpus/dfa633d05f10f2cb5c32b0a767efd10bf36cf3be
new file mode 100644
index 0000000..cfb8017
--- /dev/null
+++ b/fuzz/arm_cpuinfo_corpus/dfa633d05f10f2cb5c32b0a767efd10bf36cf3be
@@ -0,0 +1,23 @@
+Processor : ARMv7 Processor rev 2 (v7l)
+processor : 0
+BogoMIPS : 13.53
+
+processor : 1
+BogoMIPS : 13.53
+
+processor : 2
+BogoMIPS : 13.53
+
+processor : 3
+BogoMIPS : 13.53
+
+Features : swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4
+CPU implementer : 0x51
+CPU architecture: 7
+CPU variant : 0x0
+CPU part : 0x06f
+CPU revision : 2
+
+Hardware : QCT APQ8064 MAKO
+Revision : 000b
+Serial : 0000000000000000