/src/openssl/crypto/err/err_save.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2023 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 | | #define OSSL_FORCE_ERR_STATE |
11 | | |
12 | | #include <openssl/err.h> |
13 | | #include "err_local.h" |
14 | | |
15 | | /* |
16 | | * Save and restore error state. |
17 | | * We are using CRYPTO_zalloc(.., NULL, 0) instead of OPENSSL_malloc() in |
18 | | * these functions to prevent mem alloc error loop. |
19 | | */ |
20 | | |
21 | | ERR_STATE *OSSL_ERR_STATE_new(void) |
22 | 2 | { |
23 | 2 | return CRYPTO_zalloc(sizeof(ERR_STATE), NULL, 0); |
24 | 2 | } |
25 | | |
26 | | void OSSL_ERR_STATE_save(ERR_STATE *es) |
27 | 0 | { |
28 | 0 | size_t i; |
29 | 0 | ERR_STATE *thread_es; |
30 | |
|
31 | 0 | if (es == NULL) |
32 | 0 | return; |
33 | | |
34 | 0 | for (i = 0; i < ERR_NUM_ERRORS; i++) |
35 | 0 | err_clear(es, i, 1); |
36 | |
|
37 | 0 | thread_es = ossl_err_get_state_int(); |
38 | 0 | if (thread_es == NULL) |
39 | 0 | return; |
40 | | |
41 | 0 | memcpy(es, thread_es, sizeof(*es)); |
42 | | /* Taking over the pointers, just clear the thread state. */ |
43 | 0 | memset(thread_es, 0, sizeof(*thread_es)); |
44 | 0 | } |
45 | | |
46 | | void OSSL_ERR_STATE_save_to_mark(ERR_STATE *es) |
47 | 0 | { |
48 | 0 | size_t i, j, count; |
49 | 0 | int top; |
50 | 0 | ERR_STATE *thread_es; |
51 | |
|
52 | 0 | if (es == NULL) |
53 | 0 | return; |
54 | | |
55 | 0 | thread_es = ossl_err_get_state_int(); |
56 | 0 | if (thread_es == NULL) { |
57 | 0 | for (i = 0; i < ERR_NUM_ERRORS; ++i) |
58 | 0 | err_clear(es, i, 1); |
59 | |
|
60 | 0 | es->top = es->bottom = 0; |
61 | 0 | return; |
62 | 0 | } |
63 | | |
64 | | /* Determine number of errors we are going to move. */ |
65 | 0 | for (count = 0, top = thread_es->top; |
66 | 0 | thread_es->bottom != top |
67 | 0 | && thread_es->err_marks[top] == 0; |
68 | 0 | ++count) |
69 | 0 | top = top > 0 ? top - 1 : ERR_NUM_ERRORS - 1; |
70 | | |
71 | | /* Move the errors, preserving order. */ |
72 | 0 | for (i = 0, j = top; i < count; ++i) { |
73 | 0 | j = (j + 1) % ERR_NUM_ERRORS; |
74 | |
|
75 | 0 | err_clear(es, i, 1); |
76 | | |
77 | | /* Move the error entry to the given ERR_STATE. */ |
78 | 0 | es->err_flags[i] = thread_es->err_flags[j]; |
79 | 0 | es->err_marks[i] = 0; |
80 | 0 | es->err_buffer[i] = thread_es->err_buffer[j]; |
81 | 0 | es->err_data[i] = thread_es->err_data[j]; |
82 | 0 | es->err_data_size[i] = thread_es->err_data_size[j]; |
83 | 0 | es->err_data_flags[i] = thread_es->err_data_flags[j]; |
84 | 0 | es->err_file[i] = thread_es->err_file[j]; |
85 | 0 | es->err_line[i] = thread_es->err_line[j]; |
86 | 0 | es->err_func[i] = thread_es->err_func[j]; |
87 | |
|
88 | 0 | thread_es->err_flags[j] = 0; |
89 | 0 | thread_es->err_buffer[j] = 0; |
90 | 0 | thread_es->err_data[j] = NULL; |
91 | 0 | thread_es->err_data_size[j] = 0; |
92 | 0 | thread_es->err_data_flags[j] = 0; |
93 | 0 | thread_es->err_file[j] = NULL; |
94 | 0 | thread_es->err_line[j] = 0; |
95 | 0 | thread_es->err_func[j] = NULL; |
96 | 0 | } |
97 | |
|
98 | 0 | if (i > 0) { |
99 | 0 | thread_es->top = top; |
100 | | /* If we moved anything, es's stack always starts at [0]. */ |
101 | 0 | es->top = i - 1; |
102 | 0 | es->bottom = ERR_NUM_ERRORS - 1; |
103 | 0 | } else { |
104 | | /* Didn't move anything - empty stack */ |
105 | 0 | es->top = es->bottom = 0; |
106 | 0 | } |
107 | | |
108 | | /* Erase extra space as a precaution. */ |
109 | 0 | for (; i < ERR_NUM_ERRORS; ++i) |
110 | 0 | err_clear(es, i, 1); |
111 | 0 | } |
112 | | |
113 | | void OSSL_ERR_STATE_restore(const ERR_STATE *es) |
114 | 0 | { |
115 | 0 | size_t i; |
116 | 0 | ERR_STATE *thread_es; |
117 | |
|
118 | 0 | if (es == NULL || es->bottom == es->top) |
119 | 0 | return; |
120 | | |
121 | 0 | thread_es = ossl_err_get_state_int(); |
122 | 0 | if (thread_es == NULL) |
123 | 0 | return; |
124 | | |
125 | 0 | for (i = (size_t)es->bottom; i != (size_t)es->top;) { |
126 | 0 | size_t top; |
127 | |
|
128 | 0 | i = (i + 1) % ERR_NUM_ERRORS; |
129 | 0 | if ((es->err_flags[i] & ERR_FLAG_CLEAR) != 0) |
130 | 0 | continue; |
131 | | |
132 | 0 | err_get_slot(thread_es); |
133 | 0 | top = thread_es->top; |
134 | 0 | err_clear(thread_es, top, 0); |
135 | |
|
136 | 0 | thread_es->err_flags[top] = es->err_flags[i]; |
137 | 0 | thread_es->err_buffer[top] = es->err_buffer[i]; |
138 | |
|
139 | 0 | err_set_debug(thread_es, top, es->err_file[i], es->err_line[i], |
140 | 0 | es->err_func[i]); |
141 | |
|
142 | 0 | if (es->err_data[i] != NULL && es->err_data_size[i] != 0) { |
143 | 0 | void *data; |
144 | 0 | size_t data_sz = es->err_data_size[i]; |
145 | |
|
146 | 0 | data = CRYPTO_malloc(data_sz, NULL, 0); |
147 | 0 | if (data != NULL) { |
148 | 0 | memcpy(data, es->err_data[i], data_sz); |
149 | 0 | err_set_data(thread_es, top, data, data_sz, |
150 | 0 | es->err_data_flags[i] | ERR_TXT_MALLOCED); |
151 | 0 | } |
152 | 0 | } else { |
153 | 0 | err_clear_data(thread_es, top, 0); |
154 | 0 | } |
155 | 0 | } |
156 | 0 | } |