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