1 /*
2 * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (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 "internal/e_os.h"
11 #include "internal/cryptlib.h"
12 #include "internal/mem_alloc_utils.h"
13 #include "crypto/cryptlib.h"
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <limits.h>
17 #include <openssl/crypto.h>
18
19 /*
20 * the following pointers may be changed as long as 'allow_customize' is set
21 */
22 static int allow_customize = 1;
23 static CRYPTO_malloc_fn malloc_impl = CRYPTO_malloc;
24 static CRYPTO_realloc_fn realloc_impl = CRYPTO_realloc;
25 static CRYPTO_free_fn free_impl = CRYPTO_free;
26
27 #if !defined(OPENSSL_NO_CRYPTO_MDEBUG) && !defined(FIPS_MODULE)
28 # include "internal/tsan_assist.h"
29
30 # ifdef TSAN_REQUIRES_LOCKING
31 # define INCREMENT(x) /* empty */
32 # define LOAD(x) 0
33 # else /* TSAN_REQUIRES_LOCKING */
34 static TSAN_QUALIFIER int malloc_count;
35 static TSAN_QUALIFIER int realloc_count;
36 static TSAN_QUALIFIER int free_count;
37
38 # define INCREMENT(x) tsan_counter(&(x))
39 # define LOAD(x) tsan_load(&x)
40 # endif /* TSAN_REQUIRES_LOCKING */
41
42 static char md_failbuf[CRYPTO_MEM_CHECK_MAX_FS + 1];
43 static char *md_failstring = NULL;
44 static long md_count;
45 static int md_fail_percent = 0;
46 static int md_tracefd = -1;
47
48 static void parseit(void);
49 static int shouldfail(void);
50
51 # define FAILTEST() if (shouldfail()) return NULL
52
53 #else
54
55 # define INCREMENT(x) /* empty */
56 # define FAILTEST() /* empty */
57 #endif
58
CRYPTO_set_mem_functions(CRYPTO_malloc_fn malloc_fn,CRYPTO_realloc_fn realloc_fn,CRYPTO_free_fn free_fn)59 int CRYPTO_set_mem_functions(CRYPTO_malloc_fn malloc_fn,
60 CRYPTO_realloc_fn realloc_fn,
61 CRYPTO_free_fn free_fn)
62 {
63 if (!allow_customize)
64 return 0;
65 if (malloc_fn != NULL)
66 malloc_impl = malloc_fn;
67 if (realloc_fn != NULL)
68 realloc_impl = realloc_fn;
69 if (free_fn != NULL)
70 free_impl = free_fn;
71 return 1;
72 }
73
CRYPTO_get_mem_functions(CRYPTO_malloc_fn * malloc_fn,CRYPTO_realloc_fn * realloc_fn,CRYPTO_free_fn * free_fn)74 void CRYPTO_get_mem_functions(CRYPTO_malloc_fn *malloc_fn,
75 CRYPTO_realloc_fn *realloc_fn,
76 CRYPTO_free_fn *free_fn)
77 {
78 if (malloc_fn != NULL)
79 *malloc_fn = malloc_impl;
80 if (realloc_fn != NULL)
81 *realloc_fn = realloc_impl;
82 if (free_fn != NULL)
83 *free_fn = free_impl;
84 }
85
86 #if !defined(OPENSSL_NO_CRYPTO_MDEBUG) && !defined(FIPS_MODULE)
CRYPTO_get_alloc_counts(int * mcount,int * rcount,int * fcount)87 void CRYPTO_get_alloc_counts(int *mcount, int *rcount, int *fcount)
88 {
89 if (mcount != NULL)
90 *mcount = LOAD(malloc_count);
91 if (rcount != NULL)
92 *rcount = LOAD(realloc_count);
93 if (fcount != NULL)
94 *fcount = LOAD(free_count);
95 }
96
97 /*
98 * Parse a "malloc failure spec" string. This likes like a set of fields
99 * separated by semicolons. Each field has a count and an optional failure
100 * percentage. For example:
101 * 100@0;100@25;0@0
102 * or 100;100@25;0
103 * This means 100 mallocs succeed, then next 100 fail 25% of the time, and
104 * all remaining (count is zero) succeed.
105 * The failure percentge can have 2 digits after the comma. For example:
106 * 0@0.01
107 * This means 0.01% of all allocations will fail.
108 */
parseit(void)109 static void parseit(void)
110 {
111 char *semi = strchr(md_failstring, ';');
112 char *atsign;
113
114 if (semi != NULL)
115 *semi++ = '\0';
116
117 /* Get the count (atol will stop at the @ if there), and percentage */
118 md_count = atol(md_failstring);
119 atsign = strchr(md_failstring, '@');
120 md_fail_percent = atsign == NULL ? 0 : (int)(atof(atsign + 1) * 100 + 0.5);
121
122 if (semi != NULL)
123 md_failstring = semi;
124 }
125
126 /*
127 * Windows doesn't have random() and srandom(), but it has rand() and srand().
128 * Some rand() implementations aren't good, but we're not
129 * dealing with secure randomness here.
130 */
131 # ifdef _WIN32
132 # define random() rand()
133 # define srandom(seed) srand(seed)
134 # endif
135 /*
136 * See if the current malloc should fail.
137 */
shouldfail(void)138 static int shouldfail(void)
139 {
140 int roll = (int)(random() % 10000);
141 int shoulditfail = roll < md_fail_percent;
142 # ifndef _WIN32
143 /* suppressed on Windows as POSIX-like file descriptors are non-inheritable */
144 int len;
145 char buff[80];
146
147 if (md_tracefd > 0) {
148 BIO_snprintf(buff, sizeof(buff),
149 "%c C%ld %%%d R%d\n",
150 shoulditfail ? '-' : '+', md_count, md_fail_percent, roll);
151 len = strlen(buff);
152 if (write(md_tracefd, buff, len) != len)
153 perror("shouldfail write failed");
154 }
155 # endif
156
157 if (md_count) {
158 /* If we used up this one, go to the next. */
159 if (--md_count == 0)
160 parseit();
161 }
162
163 return shoulditfail;
164 }
165
ossl_malloc_setup_failures(void)166 void ossl_malloc_setup_failures(void)
167 {
168 const char *cp = getenv("OPENSSL_MALLOC_FAILURES");
169 size_t cplen = 0;
170
171 if (cp != NULL) {
172 /* if the value is too long we'll just ignore it */
173 cplen = strlen(cp);
174 if (cplen <= CRYPTO_MEM_CHECK_MAX_FS) {
175 strncpy(md_failbuf, cp, CRYPTO_MEM_CHECK_MAX_FS);
176 md_failstring = md_failbuf;
177 parseit();
178 }
179 }
180 if ((cp = getenv("OPENSSL_MALLOC_FD")) != NULL)
181 md_tracefd = atoi(cp);
182 if ((cp = getenv("OPENSSL_MALLOC_SEED")) != NULL)
183 srandom(atoi(cp));
184 }
185 #endif
186
CRYPTO_malloc(size_t num,const char * file,int line)187 void *CRYPTO_malloc(size_t num, const char *file, int line)
188 {
189 void *ptr;
190
191 INCREMENT(malloc_count);
192 if (malloc_impl != CRYPTO_malloc) {
193 ptr = malloc_impl(num, file, line);
194 if (ptr != NULL || num == 0)
195 return ptr;
196 goto err;
197 }
198
199 if (ossl_unlikely(num == 0))
200 return NULL;
201
202 FAILTEST();
203 if (allow_customize) {
204 /*
205 * Disallow customization after the first allocation. We only set this
206 * if necessary to avoid a store to the same cache line on every
207 * allocation.
208 */
209 allow_customize = 0;
210 }
211
212 ptr = malloc(num);
213 if (ossl_likely(ptr != NULL))
214 return ptr;
215 err:
216 ossl_report_alloc_err(file, line);
217 return NULL;
218 }
219
CRYPTO_zalloc(size_t num,const char * file,int line)220 void *CRYPTO_zalloc(size_t num, const char *file, int line)
221 {
222 void *ret;
223
224 ret = CRYPTO_malloc(num, file, line);
225 if (ret != NULL)
226 memset(ret, 0, num);
227
228 return ret;
229 }
230
CRYPTO_aligned_alloc(size_t num,size_t alignment,void ** freeptr,const char * file,int line)231 void *CRYPTO_aligned_alloc(size_t num, size_t alignment, void **freeptr,
232 const char *file, int line)
233 {
234 size_t alloc_bytes;
235 void *ret;
236
237 *freeptr = NULL;
238
239 #if defined(OPENSSL_SMALL_FOOTPRINT)
240 return NULL;
241 #endif
242
243 /* Ensure that alignment is a power of two */
244 if (alignment == 0 || (alignment & (alignment - 1)) != 0) {
245 ossl_report_alloc_err_inv(file, line);
246 return NULL;
247 }
248
249 /* Allow non-malloc() allocations as long as no malloc_impl is provided. */
250 if (malloc_impl == CRYPTO_malloc) {
251 #if defined(_BSD_SOURCE) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L)
252 int memalign_ret;
253
254 /* posix_memalign() requires alignment to be at least sizeof(void *) */
255 if (alignment < sizeof(void *))
256 alignment = sizeof(void *);
257
258 if ((memalign_ret = posix_memalign(&ret, alignment, num))) {
259 ret = NULL;
260 switch (memalign_ret) {
261 case EINVAL:
262 ossl_report_alloc_err_inv(file, line);
263 break;
264 case ENOMEM:
265 ossl_report_alloc_err(file, line);
266 break;
267 }
268 }
269 *freeptr = ret;
270 return ret;
271 #endif
272 }
273
274 /* we have to do this the hard way */
275
276 /*
277 * Note: Windows supports an _aligned_malloc call, but we choose
278 * not to use it here, because allocations from that function
279 * require that they be freed via _aligned_free. Given that
280 * we can't differentiate plain malloc blocks from blocks obtained
281 * via _aligned_malloc, just avoid its use entirely
282 */
283
284 if (ossl_unlikely(!ossl_size_add(num, alignment, &alloc_bytes, file, line)))
285 return NULL;
286
287 /*
288 * Step 1: Allocate an amount of memory that is <alignment>
289 * bytes bigger than requested
290 */
291 *freeptr = CRYPTO_malloc(alloc_bytes, file, line);
292 if (*freeptr == NULL)
293 return NULL;
294
295 /*
296 * Step 2: Add <alignment - 1> bytes to the pointer
297 * This will cross the alignment boundary that is
298 * requested
299 */
300 ret = (void *)((char *)*freeptr + (alignment - 1));
301
302 /*
303 * Step 3: Use the alignment as a mask to translate the
304 * least significant bits of the allocation at the alignment
305 * boundary to 0. ret now holds a pointer to the memory
306 * buffer at the requested alignment
307 * NOTE: It is a documented requirement that alignment be a
308 * power of 2, which is what allows this to work
309 */
310 ret = (void *)((uintptr_t)ret & (uintptr_t)(~(alignment - 1)));
311 return ret;
312 }
313
CRYPTO_realloc(void * str,size_t num,const char * file,int line)314 void *CRYPTO_realloc(void *str, size_t num, const char *file, int line)
315 {
316 void *ret;
317
318 INCREMENT(realloc_count);
319 if (realloc_impl != CRYPTO_realloc) {
320 ret = realloc_impl(str, num, file, line);
321
322 if (num == 0 || ret != NULL)
323 return ret;
324
325 goto err;
326 }
327
328 if (str == NULL)
329 return CRYPTO_malloc(num, file, line);
330
331 if (num == 0) {
332 CRYPTO_free(str, file, line);
333 return NULL;
334 }
335
336 FAILTEST();
337 ret = realloc(str, num);
338
339 err:
340 if (num != 0 && ret == NULL)
341 ossl_report_alloc_err(file, line);
342
343 return ret;
344 }
345
CRYPTO_clear_realloc(void * str,size_t old_len,size_t num,const char * file,int line)346 void *CRYPTO_clear_realloc(void *str, size_t old_len, size_t num,
347 const char *file, int line)
348 {
349 void *ret = NULL;
350
351 if (str == NULL)
352 return CRYPTO_malloc(num, file, line);
353
354 if (num == 0) {
355 CRYPTO_clear_free(str, old_len, file, line);
356 return NULL;
357 }
358
359 /* Can't shrink the buffer since memcpy below copies |old_len| bytes. */
360 if (num < old_len) {
361 OPENSSL_cleanse((char*)str + num, old_len - num);
362 return str;
363 }
364
365 ret = CRYPTO_malloc(num, file, line);
366 if (ret != NULL) {
367 memcpy(ret, str, old_len);
368 CRYPTO_clear_free(str, old_len, file, line);
369 }
370 return ret;
371 }
372
CRYPTO_free(void * str,const char * file,int line)373 void CRYPTO_free(void *str, const char *file, int line)
374 {
375 INCREMENT(free_count);
376 if (free_impl != CRYPTO_free) {
377 free_impl(str, file, line);
378 return;
379 }
380
381 free(str);
382 }
383
CRYPTO_clear_free(void * str,size_t num,const char * file,int line)384 void CRYPTO_clear_free(void *str, size_t num, const char *file, int line)
385 {
386 if (str == NULL)
387 return;
388 if (num)
389 OPENSSL_cleanse(str, num);
390 CRYPTO_free(str, file, line);
391 }
392
393 #if !defined(OPENSSL_NO_CRYPTO_MDEBUG)
394
395 # ifndef OPENSSL_NO_DEPRECATED_3_0
CRYPTO_mem_ctrl(int mode)396 int CRYPTO_mem_ctrl(int mode)
397 {
398 (void)mode;
399 return -1;
400 }
401
CRYPTO_set_mem_debug(int flag)402 int CRYPTO_set_mem_debug(int flag)
403 {
404 (void)flag;
405 return -1;
406 }
407
CRYPTO_mem_debug_push(const char * info,const char * file,int line)408 int CRYPTO_mem_debug_push(const char *info, const char *file, int line)
409 {
410 (void)info; (void)file; (void)line;
411 return 0;
412 }
413
CRYPTO_mem_debug_pop(void)414 int CRYPTO_mem_debug_pop(void)
415 {
416 return 0;
417 }
418
CRYPTO_mem_debug_malloc(void * addr,size_t num,int flag,const char * file,int line)419 void CRYPTO_mem_debug_malloc(void *addr, size_t num, int flag,
420 const char *file, int line)
421 {
422 (void)addr; (void)num; (void)flag; (void)file; (void)line;
423 }
424
CRYPTO_mem_debug_realloc(void * addr1,void * addr2,size_t num,int flag,const char * file,int line)425 void CRYPTO_mem_debug_realloc(void *addr1, void *addr2, size_t num, int flag,
426 const char *file, int line)
427 {
428 (void)addr1; (void)addr2; (void)num; (void)flag; (void)file; (void)line;
429 }
430
CRYPTO_mem_debug_free(void * addr,int flag,const char * file,int line)431 void CRYPTO_mem_debug_free(void *addr, int flag,
432 const char *file, int line)
433 {
434 (void)addr; (void)flag; (void)file; (void)line;
435 }
436
CRYPTO_mem_leaks(BIO * b)437 int CRYPTO_mem_leaks(BIO *b)
438 {
439 (void)b;
440 return -1;
441 }
442
443 # ifndef OPENSSL_NO_STDIO
CRYPTO_mem_leaks_fp(FILE * fp)444 int CRYPTO_mem_leaks_fp(FILE *fp)
445 {
446 (void)fp;
447 return -1;
448 }
449 # endif
450
CRYPTO_mem_leaks_cb(int (* cb)(const char * str,size_t len,void * u),void * u)451 int CRYPTO_mem_leaks_cb(int (*cb)(const char *str, size_t len, void *u),
452 void *u)
453 {
454 (void)cb; (void)u;
455 return -1;
456 }
457
458 # endif
459
460 #endif
461