Преглед на файлове

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>
kris/onging/CECPQ3_patch15
David Benjamin преди 6 години
committed by CQ bot account: commit-bot@chromium.org
родител
ревизия
4f746a9073
променени са 3 файла, в които са добавени 149 реда и са изтрити 161 реда
  1. +1
    -151
      crypto/cpu-arm-linux.c
  2. +148
    -6
      crypto/cpu-arm-linux.h
  3. +0
    -4
      crypto/cpu-arm-linux_test.cc

+ 1
- 151
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


+ 148
- 6
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 @@ 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


+ 0
- 4
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 @@ TEST(ARMLinuxTest, CPUInfo) {
EXPECT_EQ(t.broken_neon ? 1 : 0, crypto_cpuinfo_has_broken_neon(&sp));
}
}

#endif // !BORINGSSL_SHARED_LIBRARY

Зареждане…
Отказ
Запис