Commit c37c1a8c authored by agl@chromium.org's avatar agl@chromium.org

Disable Poly1305 code only on bad chips.

This change detects buggy ARM chips and disables the Poly1305 code only on
those chips.

BUG=341598

Review URL: https://codereview.chromium.org/442863003

Cr-Commit-Position: refs/heads/master@{#288267}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@288267 0039d316-1c4b-4281-b951-d872f2087c98
parent 3e0c8ca4
...@@ -4,11 +4,13 @@ ...@@ -4,11 +4,13 @@
#include "base/cpu.h" #include "base/cpu.h"
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <algorithm> #include <algorithm>
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/strings/string_piece.h"
#include "build/build_config.h" #include "build/build_config.h"
#if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
...@@ -44,6 +46,7 @@ CPU::CPU() ...@@ -44,6 +46,7 @@ CPU::CPU()
has_avx_hardware_(false), has_avx_hardware_(false),
has_aesni_(false), has_aesni_(false),
has_non_stop_time_stamp_counter_(false), has_non_stop_time_stamp_counter_(false),
has_broken_neon_(false),
cpu_vendor_("unknown") { cpu_vendor_("unknown") {
Initialize(); Initialize();
} }
...@@ -90,52 +93,99 @@ uint64 _xgetbv(uint32 xcr) { ...@@ -90,52 +93,99 @@ uint64 _xgetbv(uint32 xcr) {
#endif // ARCH_CPU_X86_FAMILY #endif // ARCH_CPU_X86_FAMILY
#if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) #if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
class LazyCpuInfoValue {
// Returns the string found in /proc/cpuinfo under the key "model name" or public:
// "Processor". "model name" is used in Linux 3.8 and later (3.7 and later for LazyCpuInfoValue() : has_broken_neon_(false) {
// arm64) and is shown once per CPU. "Processor" is used in earler versions and // This function finds the value from /proc/cpuinfo under the key "model
// is shown only once at the top of /proc/cpuinfo regardless of the number CPUs. // name" or "Processor". "model name" is used in Linux 3.8 and later (3.7
std::string ParseCpuInfo() { // and later for arm64) and is shown once per CPU. "Processor" is used in
// earler versions and is shown only once at the top of /proc/cpuinfo
// regardless of the number CPUs.
const char kModelNamePrefix[] = "model name\t: "; const char kModelNamePrefix[] = "model name\t: ";
const char kProcessorPrefix[] = "Processor\t: "; const char kProcessorPrefix[] = "Processor\t: ";
// This function also calculates whether we believe that this CPU has a
// broken NEON unit based on these fields from cpuinfo:
unsigned implementer = 0, architecture = 0, variant = 0, part = 0,
revision = 0;
const struct {
const char key[17];
unsigned *result;
} kUnsignedValues[] = {
{"CPU implementer", &implementer},
{"CPU architecture", &architecture},
{"CPU variant", &variant},
{"CPU part", &part},
{"CPU revision", &revision},
};
std::string contents; std::string contents;
ReadFileToString(FilePath("/proc/cpuinfo"), &contents); ReadFileToString(FilePath("/proc/cpuinfo"), &contents);
DCHECK(!contents.empty()); DCHECK(!contents.empty());
std::string cpu_brand; if (contents.empty()) {
if (!contents.empty()) { return;
}
std::istringstream iss(contents); std::istringstream iss(contents);
std::string line; std::string line;
while (std::getline(iss, line)) { while (std::getline(iss, line)) {
if (line.compare(0, strlen(kModelNamePrefix), kModelNamePrefix) == 0) { if (brand_.empty() &&
cpu_brand.assign(line.substr(strlen(kModelNamePrefix))); (line.compare(0, strlen(kModelNamePrefix), kModelNamePrefix) == 0 ||
break; line.compare(0, strlen(kProcessorPrefix), kProcessorPrefix) == 0)) {
brand_.assign(line.substr(strlen(kModelNamePrefix)));
}
for (size_t i = 0; i < arraysize(kUnsignedValues); i++) {
const char *key = kUnsignedValues[i].key;
const size_t len = strlen(key);
if (line.compare(0, len, key) == 0 &&
line.size() >= len + 1 &&
(line[len] == '\t' || line[len] == ' ' || line[len] == ':')) {
size_t colon_pos = line.find(':', len);
if (colon_pos == std::string::npos) {
continue;
}
const StringPiece line_sp(line);
StringPiece value_sp = line_sp.substr(colon_pos + 1);
while (!value_sp.empty() &&
(value_sp[0] == ' ' || value_sp[0] == '\t')) {
value_sp = value_sp.substr(1);
}
// The string may have leading "0x" or not, so we use strtoul to
// handle that.
char *endptr;
std::string value(value_sp.as_string());
unsigned long int result = strtoul(value.c_str(), &endptr, 0);
if (*endptr == 0 && result <= UINT_MAX) {
*kUnsignedValues[i].result = result;
} }
if (line.compare(0, strlen(kProcessorPrefix), kProcessorPrefix) == 0) {
cpu_brand.assign(line.substr(strlen(kProcessorPrefix)));
break;
} }
} }
} }
return cpu_brand;
}
class LazyCpuInfoValue { has_broken_neon_ =
public: implementer == 0x51 &&
LazyCpuInfoValue() : value_(ParseCpuInfo()) {} architecture == 7 &&
const std::string& value() { return value_; } variant == 1 &&
part == 0x4d &&
revision == 0;
}
const std::string& brand() const { return brand_; }
bool has_broken_neon() const { return has_broken_neon_; }
private: private:
const std::string value_; std::string brand_;
bool has_broken_neon_;
DISALLOW_COPY_AND_ASSIGN(LazyCpuInfoValue); DISALLOW_COPY_AND_ASSIGN(LazyCpuInfoValue);
}; };
base::LazyInstance<LazyCpuInfoValue> g_lazy_cpu_brand = base::LazyInstance<LazyCpuInfoValue>::Leaky g_lazy_cpuinfo =
LAZY_INSTANCE_INITIALIZER; LAZY_INSTANCE_INITIALIZER;
const std::string& CpuBrandInfo() {
return g_lazy_cpu_brand.Get().value();
}
#endif // defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || #endif // defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) ||
// defined(OS_LINUX)) // defined(OS_LINUX))
...@@ -219,7 +269,8 @@ void CPU::Initialize() { ...@@ -219,7 +269,8 @@ void CPU::Initialize() {
has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0; has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0;
} }
#elif defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX)) #elif defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
cpu_brand_.assign(CpuBrandInfo()); cpu_brand_.assign(g_lazy_cpuinfo.Get().brand());
has_broken_neon_ = g_lazy_cpuinfo.Get().has_broken_neon();
#endif #endif
} }
......
...@@ -56,6 +56,11 @@ class BASE_EXPORT CPU { ...@@ -56,6 +56,11 @@ class BASE_EXPORT CPU {
bool has_non_stop_time_stamp_counter() const { bool has_non_stop_time_stamp_counter() const {
return has_non_stop_time_stamp_counter_; return has_non_stop_time_stamp_counter_;
} }
// has_broken_neon is only valid on ARM chips. If true, it indicates that we
// believe that the NEON unit on the current CPU is flawed and cannot execute
// some code. See https://code.google.com/p/chromium/issues/detail?id=341598
bool has_broken_neon() const { return has_broken_neon_; }
IntelMicroArchitecture GetIntelMicroArchitecture() const; IntelMicroArchitecture GetIntelMicroArchitecture() const;
const std::string& cpu_brand() const { return cpu_brand_; } const std::string& cpu_brand() const { return cpu_brand_; }
...@@ -81,6 +86,7 @@ class BASE_EXPORT CPU { ...@@ -81,6 +86,7 @@ class BASE_EXPORT CPU {
bool has_avx_hardware_; bool has_avx_hardware_;
bool has_aesni_; bool has_aesni_;
bool has_non_stop_time_stamp_counter_; bool has_non_stop_time_stamp_counter_;
bool has_broken_neon_;
std::string cpu_vendor_; std::string cpu_vendor_;
std::string cpu_brand_; std::string cpu_brand_;
}; };
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#if defined(OS_ANDROID) && defined(ARCH_CPU_ARMEL) #if defined(OS_ANDROID) && defined(ARCH_CPU_ARMEL)
#include <cpu-features.h> #include <cpu-features.h>
#include "base/cpu.h"
#endif #endif
namespace crypto { namespace crypto {
...@@ -62,10 +63,9 @@ class OpenSSLInitSingleton { ...@@ -62,10 +63,9 @@ class OpenSSLInitSingleton {
(android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0; (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0;
if (has_neon) if (has_neon)
CRYPTO_set_NEON_capable(1); CRYPTO_set_NEON_capable(1);
// In all cases, currently, mark the NEON unit as broken because some // See https://code.google.com/p/chromium/issues/detail?id=341598
// phones can't execute the Poly1305 code correctly. See base::CPU cpu;
// https://code.google.com/p/chromium/issues/detail?id=341598 CRYPTO_set_NEON_functional(!cpu.has_broken_neon());
CRYPTO_set_NEON_functional(0);
#endif #endif
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment