Coverage Report

Created: 2023-06-07 07:13

/src/boringssl/crypto/stack/stack.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2
 * All rights reserved.
3
 *
4
 * This package is an SSL implementation written
5
 * by Eric Young (eay@cryptsoft.com).
6
 * The implementation was written so as to conform with Netscapes SSL.
7
 *
8
 * This library is free for commercial and non-commercial use as long as
9
 * the following conditions are aheared to.  The following conditions
10
 * apply to all code found in this distribution, be it the RC4, RSA,
11
 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
12
 * included with this distribution is covered by the same copyright terms
13
 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14
 *
15
 * Copyright remains Eric Young's, and as such any Copyright notices in
16
 * the code are not to be removed.
17
 * If this package is used in a product, Eric Young should be given attribution
18
 * as the author of the parts of the library used.
19
 * This can be in the form of a textual message at program startup or
20
 * in documentation (online or textual) provided with the package.
21
 *
22
 * Redistribution and use in source and binary forms, with or without
23
 * modification, are permitted provided that the following conditions
24
 * are met:
25
 * 1. Redistributions of source code must retain the copyright
26
 *    notice, this list of conditions and the following disclaimer.
27
 * 2. Redistributions in binary form must reproduce the above copyright
28
 *    notice, this list of conditions and the following disclaimer in the
29
 *    documentation and/or other materials provided with the distribution.
30
 * 3. All advertising materials mentioning features or use of this software
31
 *    must display the following acknowledgement:
32
 *    "This product includes cryptographic software written by
33
 *     Eric Young (eay@cryptsoft.com)"
34
 *    The word 'cryptographic' can be left out if the rouines from the library
35
 *    being used are not cryptographic related :-).
36
 * 4. If you include any Windows specific code (or a derivative thereof) from
37
 *    the apps directory (application code) you must include an acknowledgement:
38
 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39
 *
40
 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50
 * SUCH DAMAGE.
51
 *
52
 * The licence and distribution terms for any publically available version or
53
 * derivative of this code cannot be changed.  i.e. this code cannot simply be
54
 * copied and put under another distribution licence
55
 * [including the GNU Public Licence.] */
56
57
#include <openssl/stack.h>
58
59
#include <assert.h>
60
#include <limits.h>
61
62
#include <openssl/err.h>
63
#include <openssl/mem.h>
64
65
#include "../internal.h"
66
67
68
// kMinSize is the number of pointers that will be initially allocated in a new
69
// stack.
70
static const size_t kMinSize = 4;
71
72
3.26M
_STACK *sk_new(OPENSSL_sk_cmp_func comp) {
73
3.26M
  _STACK *ret = OPENSSL_malloc(sizeof(_STACK));
74
3.26M
  if (ret == NULL) {
75
0
    return NULL;
76
0
  }
77
3.26M
  OPENSSL_memset(ret, 0, sizeof(_STACK));
78
79
3.26M
  ret->data = OPENSSL_malloc(sizeof(void *) * kMinSize);
80
3.26M
  if (ret->data == NULL) {
81
0
    goto err;
82
0
  }
83
84
3.26M
  OPENSSL_memset(ret->data, 0, sizeof(void *) * kMinSize);
85
86
3.26M
  ret->comp = comp;
87
3.26M
  ret->num_alloc = kMinSize;
88
89
3.26M
  return ret;
90
91
0
err:
92
0
  OPENSSL_free(ret);
93
0
  return NULL;
94
3.26M
}
95
96
3.26M
_STACK *sk_new_null(void) { return sk_new(NULL); }
97
98
54.2M
size_t sk_num(const _STACK *sk) {
99
54.2M
  if (sk == NULL) {
100
436k
    return 0;
101
436k
  }
102
53.8M
  return sk->num;
103
54.2M
}
104
105
0
void sk_zero(_STACK *sk) {
106
0
  if (sk == NULL || sk->num == 0) {
107
0
    return;
108
0
  }
109
0
  OPENSSL_memset(sk->data, 0, sizeof(void*) * sk->num);
110
0
  sk->num = 0;
111
0
  sk->sorted = 0;
112
0
}
113
114
48.2M
void *sk_value(const _STACK *sk, size_t i) {
115
48.2M
  if (!sk || i >= sk->num) {
116
0
    return NULL;
117
0
  }
118
48.2M
  return sk->data[i];
119
48.2M
}
120
121
649k
void *sk_set(_STACK *sk, size_t i, void *value) {
122
649k
  if (!sk || i >= sk->num) {
123
0
    return NULL;
124
0
  }
125
649k
  return sk->data[i] = value;
126
649k
}
127
128
3.79M
void sk_free(_STACK *sk) {
129
3.79M
  if (sk == NULL) {
130
347k
    return;
131
347k
  }
132
3.44M
  OPENSSL_free(sk->data);
133
3.44M
  OPENSSL_free(sk);
134
3.44M
}
135
136
void sk_pop_free_ex(_STACK *sk, OPENSSL_sk_call_free_func call_free_func,
137
3.46M
                    OPENSSL_sk_free_func free_func) {
138
3.46M
  if (sk == NULL) {
139
1.02M
    return;
140
1.02M
  }
141
142
6.68M
  for (size_t i = 0; i < sk->num; i++) {
143
4.24M
    if (sk->data[i] != NULL) {
144
4.22M
      call_free_func(free_func, sk->data[i]);
145
4.22M
    }
146
4.24M
  }
147
2.43M
  sk_free(sk);
148
2.43M
}
149
150
// Historically, |sk_pop_free| called the function as |OPENSSL_sk_free_func|
151
// directly. This is undefined in C. Some callers called |sk_pop_free| directly,
152
// so we must maintain a compatibility version for now.
153
0
static void call_free_func_legacy(OPENSSL_sk_free_func func, void *ptr) {
154
0
  func(ptr);
155
0
}
156
157
0
void sk_pop_free(_STACK *sk, OPENSSL_sk_free_func free_func) {
158
0
  sk_pop_free_ex(sk, call_free_func_legacy, free_func);
159
0
}
160
161
5.73M
size_t sk_insert(_STACK *sk, void *p, size_t where) {
162
5.73M
  if (sk == NULL) {
163
0
    return 0;
164
0
  }
165
166
5.73M
  if (sk->num >= INT_MAX) {
167
0
    OPENSSL_PUT_ERROR(CRYPTO, ERR_R_OVERFLOW);
168
0
    return 0;
169
0
  }
170
171
5.73M
  if (sk->num_alloc <= sk->num + 1) {
172
    // Attempt to double the size of the array.
173
201k
    size_t new_alloc = sk->num_alloc << 1;
174
201k
    size_t alloc_size = new_alloc * sizeof(void *);
175
201k
    void **data;
176
177
    // If the doubling overflowed, try to increment.
178
201k
    if (new_alloc < sk->num_alloc || alloc_size / sizeof(void *) != new_alloc) {
179
0
      new_alloc = sk->num_alloc + 1;
180
0
      alloc_size = new_alloc * sizeof(void *);
181
0
    }
182
183
    // If the increment also overflowed, fail.
184
201k
    if (new_alloc < sk->num_alloc || alloc_size / sizeof(void *) != new_alloc) {
185
0
      return 0;
186
0
    }
187
188
201k
    data = OPENSSL_realloc(sk->data, alloc_size);
189
201k
    if (data == NULL) {
190
0
      return 0;
191
0
    }
192
193
201k
    sk->data = data;
194
201k
    sk->num_alloc = new_alloc;
195
201k
  }
196
197
5.73M
  if (where >= sk->num) {
198
5.73M
    sk->data[sk->num] = p;
199
5.73M
  } else {
200
0
    OPENSSL_memmove(&sk->data[where + 1], &sk->data[where],
201
0
                    sizeof(void *) * (sk->num - where));
202
0
    sk->data[where] = p;
203
0
  }
204
205
5.73M
  sk->num++;
206
5.73M
  sk->sorted = 0;
207
208
5.73M
  return sk->num;
209
5.73M
}
210
211
2.96k
void *sk_delete(_STACK *sk, size_t where) {
212
2.96k
  void *ret;
213
214
2.96k
  if (!sk || where >= sk->num) {
215
0
    return NULL;
216
0
  }
217
218
2.96k
  ret = sk->data[where];
219
220
2.96k
  if (where != sk->num - 1) {
221
2.95k
    OPENSSL_memmove(&sk->data[where], &sk->data[where + 1],
222
2.95k
                    sizeof(void *) * (sk->num - where - 1));
223
2.95k
  }
224
225
2.96k
  sk->num--;
226
2.96k
  return ret;
227
2.96k
}
228
229
2.95k
void *sk_delete_ptr(_STACK *sk, const void *p) {
230
2.95k
  if (sk == NULL) {
231
0
    return NULL;
232
0
  }
233
234
9.43k
  for (size_t i = 0; i < sk->num; i++) {
235
9.43k
    if (sk->data[i] == p) {
236
2.95k
      return sk_delete(sk, i);
237
2.95k
    }
238
9.43k
  }
239
240
0
  return NULL;
241
2.95k
}
242
243
void sk_delete_if(_STACK *sk, OPENSSL_sk_call_delete_if_func call_func,
244
0
                  OPENSSL_sk_delete_if_func func, void *data) {
245
0
  if (sk == NULL) {
246
0
    return;
247
0
  }
248
249
0
  size_t new_num = 0;
250
0
  for (size_t i = 0; i < sk->num; i++) {
251
0
    if (!call_func(func, sk->data[i], data)) {
252
0
      sk->data[new_num] = sk->data[i];
253
0
      new_num++;
254
0
    }
255
0
  }
256
0
  sk->num = new_num;
257
0
}
258
259
int sk_find(const _STACK *sk, size_t *out_index, const void *p,
260
68.8k
            OPENSSL_sk_call_cmp_func call_cmp_func) {
261
68.8k
  if (sk == NULL) {
262
0
    return 0;
263
0
  }
264
265
68.8k
  if (sk->comp == NULL) {
266
    // Use pointer equality when no comparison function has been set.
267
694k
    for (size_t i = 0; i < sk->num; i++) {
268
694k
      if (sk->data[i] == p) {
269
68.6k
        if (out_index) {
270
5.00k
          *out_index = i;
271
5.00k
        }
272
68.6k
        return 1;
273
68.6k
      }
274
694k
    }
275
180
    return 0;
276
68.8k
  }
277
278
0
  if (p == NULL) {
279
0
    return 0;
280
0
  }
281
282
0
  if (!sk_is_sorted(sk)) {
283
0
    for (size_t i = 0; i < sk->num; i++) {
284
0
      const void *elem = sk->data[i];
285
0
      if (call_cmp_func(sk->comp, &p, &elem) == 0) {
286
0
        if (out_index) {
287
0
          *out_index = i;
288
0
        }
289
0
        return 1;
290
0
      }
291
0
    }
292
0
    return 0;
293
0
  }
294
295
  // The stack is sorted, so binary search to find the element.
296
  //
297
  // |lo| and |hi| maintain a half-open interval of where the answer may be. All
298
  // indices such that |lo <= idx < hi| are candidates.
299
0
  size_t lo = 0, hi = sk->num;
300
0
  while (lo < hi) {
301
    // Bias |mid| towards |lo|. See the |r == 0| case below.
302
0
    size_t mid = lo + (hi - lo - 1) / 2;
303
0
    assert(lo <= mid && mid < hi);
304
0
    const void *elem = sk->data[mid];
305
0
    int r = call_cmp_func(sk->comp, &p, &elem);
306
0
    if (r > 0) {
307
0
      lo = mid + 1;  // |mid| is too low.
308
0
    } else if (r < 0) {
309
0
      hi = mid;  // |mid| is too high.
310
0
    } else {
311
      // |mid| matches. However, this function returns the earliest match, so we
312
      // can only return if the range has size one.
313
0
      if (hi - lo == 1) {
314
0
        if (out_index != NULL) {
315
0
          *out_index = mid;
316
0
        }
317
0
        return 1;
318
0
      }
319
      // The sample is biased towards |lo|. |mid| can only be |hi - 1| if
320
      // |hi - lo| was one, so this makes forward progress.
321
0
      assert(mid + 1 < hi);
322
0
      hi = mid + 1;
323
0
    }
324
0
  }
325
326
0
  assert(lo == hi);
327
0
  return 0;  // Not found.
328
0
}
329
330
0
void *sk_shift(_STACK *sk) {
331
0
  if (sk == NULL) {
332
0
    return NULL;
333
0
  }
334
0
  if (sk->num == 0) {
335
0
    return NULL;
336
0
  }
337
0
  return sk_delete(sk, 0);
338
0
}
339
340
5.54M
size_t sk_push(_STACK *sk, void *p) { return (sk_insert(sk, p, sk->num)); }
341
342
3
void *sk_pop(_STACK *sk) {
343
3
  if (sk == NULL) {
344
0
    return NULL;
345
0
  }
346
3
  if (sk->num == 0) {
347
0
    return NULL;
348
0
  }
349
3
  return sk_delete(sk, sk->num - 1);
350
3
}
351
352
181k
_STACK *sk_dup(const _STACK *sk) {
353
181k
  if (sk == NULL) {
354
0
    return NULL;
355
0
  }
356
357
181k
  _STACK *ret = OPENSSL_malloc(sizeof(_STACK));
358
181k
  if (ret == NULL) {
359
0
    return NULL;
360
0
  }
361
181k
  OPENSSL_memset(ret, 0, sizeof(_STACK));
362
363
181k
  ret->data = OPENSSL_malloc(sizeof(void *) * sk->num_alloc);
364
181k
  if (ret->data == NULL) {
365
0
    goto err;
366
0
  }
367
368
181k
  ret->num = sk->num;
369
181k
  OPENSSL_memcpy(ret->data, sk->data, sizeof(void *) * sk->num);
370
181k
  ret->sorted = sk->sorted;
371
181k
  ret->num_alloc = sk->num_alloc;
372
181k
  ret->comp = sk->comp;
373
181k
  return ret;
374
375
0
err:
376
0
  sk_free(ret);
377
0
  return NULL;
378
181k
}
379
380
#if defined(_MSC_VER)
381
struct sort_compare_ctx {
382
  OPENSSL_sk_call_cmp_func call_cmp_func;
383
  OPENSSL_sk_cmp_func cmp_func;
384
};
385
386
static int sort_compare(void *ctx_v, const void *a, const void *b) {
387
  struct sort_compare_ctx *ctx = ctx_v;
388
  return ctx->call_cmp_func(ctx->cmp_func, a, b);
389
}
390
#endif
391
392
0
void sk_sort(_STACK *sk, OPENSSL_sk_call_cmp_func call_cmp_func) {
393
0
  if (sk == NULL || sk->comp == NULL || sk->sorted) {
394
0
    return;
395
0
  }
396
397
0
  if (sk->num >= 2) {
398
#if defined(_MSC_VER)
399
    // MSVC's |qsort_s| is different from the C11 one.
400
    // https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/qsort-s?view=msvc-170
401
    struct sort_compare_ctx ctx = {call_cmp_func, sk->comp};
402
    qsort_s(sk->data, sk->num, sizeof(void *), sort_compare, &ctx);
403
#else
404
    // sk->comp is a function that takes pointers to pointers to elements, but
405
    // qsort take a comparison function that just takes pointers to elements.
406
    // However, since we're passing an array of pointers to qsort, we can just
407
    // cast the comparison function and everything works.
408
    //
409
    // TODO(davidben): This is undefined behavior, but the call is in libc so,
410
    // e.g., CFI does not notice. |qsort| is missing a void* parameter in its
411
    // callback, while no one defines |qsort_r| or |qsort_s| consistently. See
412
    // https://stackoverflow.com/a/39561369
413
0
    int (*comp_func)(const void *, const void *) =
414
0
        (int (*)(const void *, const void *))(sk->comp);
415
0
    qsort(sk->data, sk->num, sizeof(void *), comp_func);
416
0
#endif
417
0
  }
418
0
  sk->sorted = 1;
419
0
}
420
421
0
int sk_is_sorted(const _STACK *sk) {
422
0
  if (!sk) {
423
0
    return 1;
424
0
  }
425
  // Zero- and one-element lists are always sorted.
426
0
  return sk->sorted || (sk->comp != NULL && sk->num < 2);
427
0
}
428
429
0
OPENSSL_sk_cmp_func sk_set_cmp_func(_STACK *sk, OPENSSL_sk_cmp_func comp) {
430
0
  OPENSSL_sk_cmp_func old = sk->comp;
431
432
0
  if (sk->comp != comp) {
433
0
    sk->sorted = 0;
434
0
  }
435
0
  sk->comp = comp;
436
437
0
  return old;
438
0
}
439
440
_STACK *sk_deep_copy(const _STACK *sk, OPENSSL_sk_call_copy_func call_copy_func,
441
                     OPENSSL_sk_copy_func copy_func,
442
                     OPENSSL_sk_call_free_func call_free_func,
443
125k
                     OPENSSL_sk_free_func free_func) {
444
125k
  _STACK *ret = sk_dup(sk);
445
125k
  if (ret == NULL) {
446
0
    return NULL;
447
0
  }
448
449
254k
  for (size_t i = 0; i < ret->num; i++) {
450
129k
    if (ret->data[i] == NULL) {
451
506
      continue;
452
506
    }
453
129k
    ret->data[i] = call_copy_func(copy_func, ret->data[i]);
454
129k
    if (ret->data[i] == NULL) {
455
0
      for (size_t j = 0; j < i; j++) {
456
0
        if (ret->data[j] != NULL) {
457
0
          call_free_func(free_func, ret->data[j]);
458
0
        }
459
0
      }
460
0
      sk_free(ret);
461
0
      return NULL;
462
0
    }
463
129k
  }
464
465
125k
  return ret;
466
125k
}