1 /*
2 * Copyright 2025 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 /*
11 * Utility overflow checking and reporting functions
12 */
13
14 #ifndef OSSL_INTERNAL_CHECK_SIZE_OVERFLOW_H
15 # define OSSL_INTERNAL_CHECK_SIZE_OVERFLOW_H
16
17 # include <limits.h>
18 # include <stdbool.h>
19 # include <stdint.h>
20
21 # include "internal/common.h"
22 # include "internal/safe_math.h"
23
24 # include <openssl/cryptoerr.h>
25 # include <openssl/err.h>
26
OSSL_SAFE_MATH_UNSIGNED(size_t,size_t)27 OSSL_SAFE_MATH_UNSIGNED(size_t, size_t)
28
29 /*
30 * A helper routine to report memory allocation errors.
31 * Similar to the ERR_raise() macro, but accepts explicit file/line arguments,
32 * pre-defines the library to ERR_LIB_CRYPTO, and avoids emitting an error
33 * if both file set to NULL and line set to 0.
34 */
35 static ossl_inline ossl_unused void
36 ossl_report_alloc_err_ex(const char * const file, const int line,
37 const int reason)
38 {
39 /*
40 * ossl_err_get_state_int() in err.c uses CRYPTO_zalloc(num, NULL, 0) for
41 * ERR_STATE allocation. Prevent mem alloc error loop while reporting error.
42 */
43 if (file != NULL || line != 0) {
44 ERR_new();
45 ERR_set_debug(file, line, NULL);
46 ERR_set_error(ERR_LIB_CRYPTO, reason, NULL);
47 }
48 }
49
50 /* Report a memory allocation failure. */
51 static ossl_inline ossl_unused void
ossl_report_alloc_err(const char * const file,const int line)52 ossl_report_alloc_err(const char * const file, const int line)
53 {
54 ossl_report_alloc_err_ex(file, line, ERR_R_MALLOC_FAILURE);
55 }
56
57 /* Report an integer overflow during allocation size calculation. */
58 static ossl_inline ossl_unused void
ossl_report_alloc_err_of(const char * const file,const int line)59 ossl_report_alloc_err_of(const char * const file, const int line)
60 {
61 ossl_report_alloc_err_ex(file, line, CRYPTO_R_INTEGER_OVERFLOW);
62 }
63
64 /* Report invalid memory allocation call arguments. */
65 static ossl_inline ossl_unused void
ossl_report_alloc_err_inv(const char * const file,const int line)66 ossl_report_alloc_err_inv(const char * const file, const int line)
67 {
68 ossl_report_alloc_err_ex(file, line, ERR_R_PASSED_INVALID_ARGUMENT);
69 }
70
71 /*
72 * Check the result of num and size multiplication for overflow
73 * and set error if it is the case; return true if there was no overflow,
74 * false if there was.
75 */
76 static ossl_inline ossl_unused bool
ossl_size_mul(const size_t num,const size_t size,size_t * bytes,const char * const file,const int line)77 ossl_size_mul(const size_t num, const size_t size, size_t *bytes,
78 const char * const file, const int line)
79 {
80 int err = 0;
81 *bytes = safe_mul_size_t(num, size, &err);
82
83 if (ossl_unlikely(err != 0)) {
84 ossl_report_alloc_err_of(file, line);
85
86 return false;
87 }
88
89 return true;
90 }
91
92 /*
93 * Check the result of size1 and size2 addition for overflow
94 * and set error if it is the case; returns true if there was no overflow,
95 * false if there was.
96 */
97 static ossl_inline ossl_unused bool
ossl_size_add(const size_t size1,const size_t size2,size_t * bytes,const char * const file,const int line)98 ossl_size_add(const size_t size1, const size_t size2, size_t *bytes,
99 const char * const file, const int line)
100 {
101 int err = 0;
102 *bytes = safe_add_size_t(size1, size2, &err);
103
104 if (ossl_unlikely(err != 0)) {
105 ossl_report_alloc_err_of(file, line);
106
107 return false;
108 }
109
110 return true;
111 }
112
113 #endif /* OSSL_INTERNAL_CHECK_SIZE_OVERFLOW_H */
114