Skip to content

Commit

Permalink
crypto/cryptlib.c: make OPENSS_cpuid_setup safe to use as constructor.
Browse files Browse the repository at this point in the history
Reviewed-by: Kurt Roeckx <kurt@roeckx.be>
(Merged from #6752)
  • Loading branch information
Andy Polyakov committed Jul 25, 2018
1 parent f529b5c commit b86d57b
Showing 1 changed file with 81 additions and 18 deletions.
99 changes: 81 additions & 18 deletions crypto/cryptlib.c
Expand Up @@ -19,29 +19,97 @@
extern unsigned int OPENSSL_ia32cap_P[4];

# if defined(OPENSSL_CPUID_OBJ) && !defined(OPENSSL_NO_ASM) && !defined(I386_ONLY)
#include <stdio.h>

/*
* Purpose of these minimalistic and character-type-agnostic subroutines
* is to break dependency on MSVCRT (on Windows) and locale. This makes
* OPENSSL_cpuid_setup safe to use as "constructor". "Character-type-
* agnostic" means that they work with either wide or 8-bit characters,
* exploiting the fact that first 127 characters can be simply casted
* between the sets, while the rest would be simply rejected by ossl_is*
* subroutines.
*/
# ifdef _WIN32
typedef WCHAR variant_char;

static variant_char *ossl_getenv(const char *name)
{
/*
* Since we pull only one environment variable, it's simpler to
* to just ignore |name| and use equivalent wide-char L-literal.
* As well as to ignore excessively long values...
*/
static WCHAR value[48];
DWORD len = GetEnvironmentVariableW(L"OPENSSL_ia32cap", value, 48);

return (len > 0 && len < 48) ? value : NULL;
}
# else
typedef char variant_char;
# define ossl_getenv getenv
# endif

# include "internal/ctype.h"

static int todigit(variant_char c)
{
if (ossl_isdigit(c))
return c - '0';
else if (ossl_isxdigit(c))
return ossl_tolower(c) - 'a' + 10;

/* return largest base value to make caller terminate the loop */
return 16;
}

static uint64_t ossl_strtouint64(const variant_char *str)
{
uint64_t ret = 0;
unsigned int digit, base = 10;

if (*str == '0') {
base = 8, str++;
if (ossl_tolower(*str) == 'x')
base = 16, str++;
}

while((digit = todigit(*str++)) < base)
ret = ret * base + digit;

return ret;
}

static variant_char *ossl_strchr(const variant_char *str, char srch)
{ variant_char c;

while((c = *str)) {
if (c == srch)
return (variant_char *)str;
str++;
}

return NULL;
}

# define OPENSSL_CPUID_SETUP
typedef uint64_t IA32CAP;

void OPENSSL_cpuid_setup(void)
{
static int trigger = 0;
IA32CAP OPENSSL_ia32_cpuid(unsigned int *);
IA32CAP vec;
char *env;
const variant_char *env;

if (trigger)
return;

trigger = 1;
if ((env = getenv("OPENSSL_ia32cap"))) {
if ((env = ossl_getenv("OPENSSL_ia32cap")) != NULL) {
int off = (env[0] == '~') ? 1 : 0;
# if defined(_WIN32)
if (!sscanf(env + off, "%I64i", &vec))
vec = strtoul(env + off, NULL, 0);
# else
if (!sscanf(env + off, "%lli", (long long *)&vec))
vec = strtoul(env + off, NULL, 0);
# endif

vec = ossl_strtouint64(env + off);

if (off) {
IA32CAP mask = vec;
vec = OPENSSL_ia32_cpuid(OPENSSL_ia32cap_P) & ~mask;
Expand All @@ -60,17 +128,12 @@ void OPENSSL_cpuid_setup(void)
vec = OPENSSL_ia32_cpuid(OPENSSL_ia32cap_P);
}

if ((env = strchr(env, ':'))) {
if ((env = ossl_strchr(env, ':')) != NULL) {
IA32CAP vecx;

env++;
off = (env[0] == '~') ? 1 : 0;
# if defined(_WIN32)
if (!sscanf(env + off, "%I64i", &vecx))
vecx = strtoul(env + off, NULL, 0);
# else
if (!sscanf(env + off, "%lli", (long long *)&vecx))
vecx = strtoul(env + off, NULL, 0);
# endif
vecx = ossl_strtouint64(env + off);
if (off) {
OPENSSL_ia32cap_P[2] &= ~(unsigned int)vecx;
OPENSSL_ia32cap_P[3] &= ~(unsigned int)(vecx >> 32);
Expand Down

0 comments on commit b86d57b

Please sign in to comment.