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