ClusterFuzz folks want to switch to a shared library build, so call into these another way. The new setup isn't quite ideal because the real code builds as C and now tests as C++, but it should work. Bug: chromium:907115 Change-Id: Ia1ffc18832739b09fee21b84ee5d181e61feaa15 Reviewed-on: https://boringssl-review.googlesource.com/c/33285 Commit-Queue: David Benjamin <davidben@google.com> Commit-Queue: Adam Langley <agl@google.com> Reviewed-by: Adam Langley <agl@google.com>kris/onging/CECPQ3_patch15
@@ -14,9 +14,6 @@ | |||
#include <openssl/cpu.h> | |||
#include "cpu-arm-linux.h" | |||
#include "internal.h" | |||
#if defined(OPENSSL_ARM) && !defined(OPENSSL_STATIC_ARMCAP) | |||
#include <errno.h> | |||
#include <fcntl.h> | |||
@@ -26,155 +23,8 @@ | |||
#include <openssl/arm_arch.h> | |||
#include <openssl/buf.h> | |||
#include <openssl/mem.h> | |||
#endif | |||
// 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); | |||
return a->len == b_len && OPENSSL_memcmp(a->data, b, b_len) == 0; | |||
} | |||
// STRING_PIECE_split finds the first occurence of |sep| in |in| and, if found, | |||
// sets |*out_left| and |*out_right| to |in| split before and after it. It | |||
// returns one if |sep| was found and zero otherwise. | |||
static int STRING_PIECE_split(STRING_PIECE *out_left, STRING_PIECE *out_right, | |||
const STRING_PIECE *in, char sep) { | |||
const char *p = OPENSSL_memchr(in->data, sep, in->len); | |||
if (p == NULL) { | |||
return 0; | |||
} | |||
// |out_left| or |out_right| may alias |in|, so make a copy. | |||
STRING_PIECE in_copy = *in; | |||
out_left->data = in_copy.data; | |||
out_left->len = p - in_copy.data; | |||
out_right->data = in_copy.data + out_left->len + 1; | |||
out_right->len = in_copy.len - out_left->len - 1; | |||
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')) { | |||
s->data++; | |||
s->len--; | |||
} | |||
while (s->len != 0 && | |||
(s->data[s->len - 1] == ' ' || s->data[s->len - 1] == '\t')) { | |||
s->len--; | |||
} | |||
} | |||
// 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 | |||
// 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_get_delimited(&remaining, &line, '\n')) { | |||
STRING_PIECE key, value; | |||
if (!STRING_PIECE_split(&key, &value, &line, ':')) { | |||
continue; | |||
} | |||
STRING_PIECE_trim(&key); | |||
if (STRING_PIECE_equals(&key, field)) { | |||
STRING_PIECE_trim(&value); | |||
*out = value; | |||
return 1; | |||
} | |||
} | |||
return 0; | |||
} | |||
static int cpuinfo_field_equals(const STRING_PIECE *cpuinfo, const char *field, | |||
const char *value) { | |||
STRING_PIECE extracted; | |||
return extract_cpuinfo_field(&extracted, cpuinfo, field) && | |||
STRING_PIECE_equals(&extracted, value); | |||
} | |||
// has_list_item treats |list| as a space-separated list of items and returns | |||
// 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_get_delimited(&remaining, &feature, ' ')) { | |||
if (STRING_PIECE_equals(&feature, item)) { | |||
return 1; | |||
} | |||
} | |||
return 0; | |||
} | |||
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 | |||
// "Features" line does not work. (For simplicity, use strict equality. We | |||
// assume everything running on future ARM architectures will have a | |||
// working |getauxval|.) | |||
return HWCAP_NEON; | |||
} | |||
STRING_PIECE features; | |||
if (extract_cpuinfo_field(&features, cpuinfo, "Features") && | |||
has_list_item(&features, "neon")) { | |||
return HWCAP_NEON; | |||
} | |||
return 0; | |||
} | |||
unsigned long crypto_get_arm_hwcap2_from_cpuinfo(const STRING_PIECE *cpuinfo) { | |||
STRING_PIECE features; | |||
if (!extract_cpuinfo_field(&features, cpuinfo, "Features")) { | |||
return 0; | |||
} | |||
unsigned long ret = 0; | |||
if (has_list_item(&features, "aes")) { | |||
ret |= HWCAP2_AES; | |||
} | |||
if (has_list_item(&features, "pmull")) { | |||
ret |= HWCAP2_PMULL; | |||
} | |||
if (has_list_item(&features, "sha1")) { | |||
ret |= HWCAP2_SHA1; | |||
} | |||
if (has_list_item(&features, "sha2")) { | |||
ret |= HWCAP2_SHA2; | |||
} | |||
return ret; | |||
} | |||
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") && | |||
cpuinfo_field_equals(cpuinfo, "CPU part", "0x04d") && | |||
cpuinfo_field_equals(cpuinfo, "CPU revision", "0"); | |||
} | |||
#if defined(OPENSSL_ARM) && !defined(OPENSSL_STATIC_ARMCAP) | |||
#include "cpu-arm-linux.h" | |||
#define AT_HWCAP 16 | |||
#define AT_HWCAP2 26 | |||
@@ -17,14 +17,17 @@ | |||
#include <openssl/base.h> | |||
#include <string.h> | |||
#include "internal.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. | |||
// The cpuinfo parser lives in a header file so it may be accessible from | |||
// cross-platform fuzzers without adding code to those platforms normally. | |||
#define HWCAP_NEON (1 << 12) | |||
@@ -40,17 +43,156 @@ typedef struct { | |||
size_t len; | |||
} STRING_PIECE; | |||
static int STRING_PIECE_equals(const STRING_PIECE *a, const char *b) { | |||
size_t b_len = strlen(b); | |||
return a->len == b_len && OPENSSL_memcmp(a->data, b, b_len) == 0; | |||
} | |||
// STRING_PIECE_split finds the first occurence of |sep| in |in| and, if found, | |||
// sets |*out_left| and |*out_right| to |in| split before and after it. It | |||
// returns one if |sep| was found and zero otherwise. | |||
static int STRING_PIECE_split(STRING_PIECE *out_left, STRING_PIECE *out_right, | |||
const STRING_PIECE *in, char sep) { | |||
const char *p = (const char *)OPENSSL_memchr(in->data, sep, in->len); | |||
if (p == NULL) { | |||
return 0; | |||
} | |||
// |out_left| or |out_right| may alias |in|, so make a copy. | |||
STRING_PIECE in_copy = *in; | |||
out_left->data = in_copy.data; | |||
out_left->len = p - in_copy.data; | |||
out_right->data = in_copy.data + out_left->len + 1; | |||
out_right->len = in_copy.len - out_left->len - 1; | |||
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')) { | |||
s->data++; | |||
s->len--; | |||
} | |||
while (s->len != 0 && | |||
(s->data[s->len - 1] == ' ' || s->data[s->len - 1] == '\t')) { | |||
s->len--; | |||
} | |||
} | |||
// 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 | |||
// 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_get_delimited(&remaining, &line, '\n')) { | |||
STRING_PIECE key, value; | |||
if (!STRING_PIECE_split(&key, &value, &line, ':')) { | |||
continue; | |||
} | |||
STRING_PIECE_trim(&key); | |||
if (STRING_PIECE_equals(&key, field)) { | |||
STRING_PIECE_trim(&value); | |||
*out = value; | |||
return 1; | |||
} | |||
} | |||
return 0; | |||
} | |||
static int cpuinfo_field_equals(const STRING_PIECE *cpuinfo, const char *field, | |||
const char *value) { | |||
STRING_PIECE extracted; | |||
return extract_cpuinfo_field(&extracted, cpuinfo, field) && | |||
STRING_PIECE_equals(&extracted, value); | |||
} | |||
// has_list_item treats |list| as a space-separated list of items and returns | |||
// 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_get_delimited(&remaining, &feature, ' ')) { | |||
if (STRING_PIECE_equals(&feature, item)) { | |||
return 1; | |||
} | |||
} | |||
return 0; | |||
} | |||
// 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); | |||
static 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 | |||
// "Features" line does not work. (For simplicity, use strict equality. We | |||
// assume everything running on future ARM architectures will have a | |||
// working |getauxval|.) | |||
return HWCAP_NEON; | |||
} | |||
STRING_PIECE features; | |||
if (extract_cpuinfo_field(&features, cpuinfo, "Features") && | |||
has_list_item(&features, "neon")) { | |||
return HWCAP_NEON; | |||
} | |||
return 0; | |||
} | |||
// 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); | |||
static unsigned long crypto_get_arm_hwcap2_from_cpuinfo( | |||
const STRING_PIECE *cpuinfo) { | |||
STRING_PIECE features; | |||
if (!extract_cpuinfo_field(&features, cpuinfo, "Features")) { | |||
return 0; | |||
} | |||
unsigned long ret = 0; | |||
if (has_list_item(&features, "aes")) { | |||
ret |= HWCAP2_AES; | |||
} | |||
if (has_list_item(&features, "pmull")) { | |||
ret |= HWCAP2_PMULL; | |||
} | |||
if (has_list_item(&features, "sha1")) { | |||
ret |= HWCAP2_SHA1; | |||
} | |||
if (has_list_item(&features, "sha2")) { | |||
ret |= HWCAP2_SHA2; | |||
} | |||
return ret; | |||
} | |||
// 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); | |||
static 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") && | |||
cpuinfo_field_equals(cpuinfo, "CPU part", "0x04d") && | |||
cpuinfo_field_equals(cpuinfo, "CPU revision", "0"); | |||
} | |||
#if defined(__cplusplus) | |||
} // extern C | |||
@@ -19,8 +19,6 @@ | |||
#include <gtest/gtest.h> | |||
#if !defined(BORINGSSL_SHARED_LIBRARY) | |||
TEST(ARMLinuxTest, CPUInfo) { | |||
struct CPUInfoTest { | |||
const char *cpuinfo; | |||
@@ -232,5 +230,3 @@ TEST(ARMLinuxTest, CPUInfo) { | |||
EXPECT_EQ(t.broken_neon ? 1 : 0, crypto_cpuinfo_has_broken_neon(&sp)); | |||
} | |||
} | |||
#endif // !BORINGSSL_SHARED_LIBRARY |