Move ARM cpuinfo functions to the header. 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>
diff --git a/crypto/cpu-arm-linux.c b/crypto/cpu-arm-linux.c index 91078bd..8fe332c 100644 --- a/crypto/cpu-arm-linux.c +++ b/crypto/cpu-arm-linux.c
@@ -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
diff --git a/crypto/cpu-arm-linux.h b/crypto/cpu-arm-linux.h index eabf4ea..e326285 100644 --- a/crypto/cpu-arm-linux.h +++ b/crypto/cpu-arm-linux.h
@@ -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 @@ 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
diff --git a/crypto/cpu-arm-linux_test.cc b/crypto/cpu-arm-linux_test.cc index 3ca6e57..2b5bc11 100644 --- a/crypto/cpu-arm-linux_test.cc +++ b/crypto/cpu-arm-linux_test.cc
@@ -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 @@ EXPECT_EQ(t.broken_neon ? 1 : 0, crypto_cpuinfo_has_broken_neon(&sp)); } } - -#endif // !BORINGSSL_SHARED_LIBRARY