1/* 2 * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the OpenSSL license (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10#include "e_os.h" 11#include "internal/cryptlib.h" 12#include "crypto/cryptlib.h" 13#include <stdio.h> 14#include <stdlib.h> 15#include <limits.h> 16#include <openssl/crypto.h> 17#ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE 18# include <execinfo.h> 19#endif 20 21/* 22 * the following pointers may be changed as long as 'allow_customize' is set 23 */ 24static int allow_customize = 1; 25 26static void *(*malloc_impl)(size_t, const char *, int) 27 = CRYPTO_malloc; 28static void *(*realloc_impl)(void *, size_t, const char *, int) 29 = CRYPTO_realloc; 30static void (*free_impl)(void *, const char *, int) 31 = CRYPTO_free; 32 33#ifndef OPENSSL_NO_CRYPTO_MDEBUG 34# include "internal/tsan_assist.h" 35 36static TSAN_QUALIFIER int malloc_count; 37static TSAN_QUALIFIER int realloc_count; 38static TSAN_QUALIFIER int free_count; 39 40# define INCREMENT(x) tsan_counter(&(x)) 41 42static char *md_failstring; 43static long md_count; 44static int md_fail_percent = 0; 45static int md_tracefd = -1; 46static int call_malloc_debug = 1; 47 48static void parseit(void); 49static int shouldfail(void); 50 51# define FAILTEST() if (shouldfail()) return NULL 52 53#else 54static int call_malloc_debug = 0; 55 56# define INCREMENT(x) /* empty */ 57# define FAILTEST() /* empty */ 58#endif 59 60int CRYPTO_set_mem_functions( 61 void *(*m)(size_t, const char *, int), 62 void *(*r)(void *, size_t, const char *, int), 63 void (*f)(void *, const char *, int)) 64{ 65 if (!allow_customize) 66 return 0; 67 if (m) 68 malloc_impl = m; 69 if (r) 70 realloc_impl = r; 71 if (f) 72 free_impl = f; 73 return 1; 74} 75 76int CRYPTO_set_mem_debug(int flag) 77{ 78 if (!allow_customize) 79 return 0; 80 call_malloc_debug = flag; 81 return 1; 82} 83 84void CRYPTO_get_mem_functions( 85 void *(**m)(size_t, const char *, int), 86 void *(**r)(void *, size_t, const char *, int), 87 void (**f)(void *, const char *, int)) 88{ 89 if (m != NULL) 90 *m = malloc_impl; 91 if (r != NULL) 92 *r = realloc_impl; 93 if (f != NULL) 94 *f = free_impl; 95} 96 97#ifndef OPENSSL_NO_CRYPTO_MDEBUG 98void CRYPTO_get_alloc_counts(int *mcount, int *rcount, int *fcount) 99{ 100 if (mcount != NULL) 101 *mcount = tsan_load(&malloc_count); 102 if (rcount != NULL) 103 *rcount = tsan_load(&realloc_count); 104 if (fcount != NULL) 105 *fcount = tsan_load(&free_count); 106} 107 108/* 109 * Parse a "malloc failure spec" string. This likes like a set of fields 110 * separated by semicolons. Each field has a count and an optional failure 111 * percentage. For example: 112 * 100@0;100@25;0@0 113 * or 100;100@25;0 114 * This means 100 mallocs succeed, then next 100 fail 25% of the time, and 115 * all remaining (count is zero) succeed. 116 */ 117static void parseit(void) 118{ 119 char *semi = strchr(md_failstring, ';'); 120 char *atsign; 121 122 if (semi != NULL) 123 *semi++ = '\0'; 124 125 /* Get the count (atol will stop at the @ if there), and percentage */ 126 md_count = atol(md_failstring); 127 atsign = strchr(md_failstring, '@'); 128 md_fail_percent = atsign == NULL ? 0 : atoi(atsign + 1); 129 130 if (semi != NULL) 131 md_failstring = semi; 132} 133 134/* 135 * Windows doesn't have random(), but it has rand() 136 * Some rand() implementations aren't good, but we're not 137 * dealing with secure randomness here. 138 */ 139# ifdef _WIN32 140# define random() rand() 141# endif 142/* 143 * See if the current malloc should fail. 144 */ 145static int shouldfail(void) 146{ 147 int roll = (int)(random() % 100); 148 int shoulditfail = roll < md_fail_percent; 149# ifndef _WIN32 150/* suppressed on Windows as POSIX-like file descriptors are non-inheritable */ 151 int len; 152 char buff[80]; 153 154 if (md_tracefd > 0) { 155 BIO_snprintf(buff, sizeof(buff), 156 "%c C%ld %%%d R%d\n", 157 shoulditfail ? '-' : '+', md_count, md_fail_percent, roll); 158 len = strlen(buff); 159 if (write(md_tracefd, buff, len) != len) 160 perror("shouldfail write failed"); 161# ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE 162 if (shoulditfail) { 163 void *addrs[30]; 164 int num = backtrace(addrs, OSSL_NELEM(addrs)); 165 166 backtrace_symbols_fd(addrs, num, md_tracefd); 167 } 168# endif 169 } 170# endif 171 172 if (md_count) { 173 /* If we used up this one, go to the next. */ 174 if (--md_count == 0) 175 parseit(); 176 } 177 178 return shoulditfail; 179} 180 181void ossl_malloc_setup_failures(void) 182{ 183 const char *cp = getenv("OPENSSL_MALLOC_FAILURES"); 184 185 if (cp != NULL && (md_failstring = strdup(cp)) != NULL) 186 parseit(); 187 if ((cp = getenv("OPENSSL_MALLOC_FD")) != NULL) 188 md_tracefd = atoi(cp); 189} 190#endif 191 192void *CRYPTO_malloc(size_t num, const char *file, int line) 193{ 194 void *ret = NULL; 195 196 INCREMENT(malloc_count); 197 if (malloc_impl != NULL && malloc_impl != CRYPTO_malloc) 198 return malloc_impl(num, file, line); 199 200 if (num == 0) 201 return NULL; 202 203 FAILTEST(); 204 if (allow_customize) { 205 /* 206 * Disallow customization after the first allocation. We only set this 207 * if necessary to avoid a store to the same cache line on every 208 * allocation. 209 */ 210 allow_customize = 0; 211 } 212#ifndef OPENSSL_NO_CRYPTO_MDEBUG 213 if (call_malloc_debug) { 214 CRYPTO_mem_debug_malloc(NULL, num, 0, file, line); 215 ret = malloc(num); 216 CRYPTO_mem_debug_malloc(ret, num, 1, file, line); 217 } else { 218 ret = malloc(num); 219 } 220#else 221 (void)(file); (void)(line); 222 ret = malloc(num); 223#endif 224 225 return ret; 226} 227 228void *CRYPTO_zalloc(size_t num, const char *file, int line) 229{ 230 void *ret = CRYPTO_malloc(num, file, line); 231 232 FAILTEST(); 233 if (ret != NULL) 234 memset(ret, 0, num); 235 return ret; 236} 237 238void *CRYPTO_realloc(void *str, size_t num, const char *file, int line) 239{ 240 INCREMENT(realloc_count); 241 if (realloc_impl != NULL && realloc_impl != &CRYPTO_realloc) 242 return realloc_impl(str, num, file, line); 243 244 FAILTEST(); 245 if (str == NULL) 246 return CRYPTO_malloc(num, file, line); 247 248 if (num == 0) { 249 CRYPTO_free(str, file, line); 250 return NULL; 251 } 252 253#ifndef OPENSSL_NO_CRYPTO_MDEBUG 254 if (call_malloc_debug) { 255 void *ret; 256 CRYPTO_mem_debug_realloc(str, NULL, num, 0, file, line); 257 ret = realloc(str, num); 258 CRYPTO_mem_debug_realloc(str, ret, num, 1, file, line); 259 return ret; 260 } 261#else 262 (void)(file); (void)(line); 263#endif 264 return realloc(str, num); 265 266} 267 268void *CRYPTO_clear_realloc(void *str, size_t old_len, size_t num, 269 const char *file, int line) 270{ 271 void *ret = NULL; 272 273 if (str == NULL) 274 return CRYPTO_malloc(num, file, line); 275 276 if (num == 0) { 277 CRYPTO_clear_free(str, old_len, file, line); 278 return NULL; 279 } 280 281 /* Can't shrink the buffer since memcpy below copies |old_len| bytes. */ 282 if (num < old_len) { 283 OPENSSL_cleanse((char*)str + num, old_len - num); 284 return str; 285 } 286 287 ret = CRYPTO_malloc(num, file, line); 288 if (ret != NULL) { 289 memcpy(ret, str, old_len); 290 CRYPTO_clear_free(str, old_len, file, line); 291 } 292 return ret; 293} 294 295void CRYPTO_free(void *str, const char *file, int line) 296{ 297 INCREMENT(free_count); 298 if (free_impl != NULL && free_impl != &CRYPTO_free) { 299 free_impl(str, file, line); 300 return; 301 } 302 303#ifndef OPENSSL_NO_CRYPTO_MDEBUG 304 if (call_malloc_debug) { 305 CRYPTO_mem_debug_free(str, 0, file, line); 306 free(str); 307 CRYPTO_mem_debug_free(str, 1, file, line); 308 } else { 309 free(str); 310 } 311#else 312 free(str); 313#endif 314} 315 316void CRYPTO_clear_free(void *str, size_t num, const char *file, int line) 317{ 318 if (str == NULL) 319 return; 320 if (num) 321 OPENSSL_cleanse(str, num); 322 CRYPTO_free(str, file, line); 323} 324