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