/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_file[j] = NULL; |
93 | 0 | thread_es->err_line[j] = 0; |
94 | 0 | thread_es->err_func[j] = NULL; |
95 | 0 | } |
96 | |
|
97 | 0 | if (i > 0) { |
98 | | /* If we moved anything, es's stack always starts at [0]. */ |
99 | 0 | es->top = i - 1; |
100 | 0 | es->bottom = ERR_NUM_ERRORS - 1; |
101 | 0 | } else { |
102 | | /* Didn't move anything - empty stack */ |
103 | 0 | es->top = es->bottom = 0; |
104 | 0 | } |
105 | | |
106 | | /* Erase extra space as a precaution. */ |
107 | 0 | for (; i < ERR_NUM_ERRORS; ++i) |
108 | 0 | err_clear(es, i, 1); |
109 | 0 | } |
110 | | |
111 | | void OSSL_ERR_STATE_restore(const ERR_STATE *es) |
112 | 0 | { |
113 | 0 | size_t i; |
114 | 0 | ERR_STATE *thread_es; |
115 | |
|
116 | 0 | if (es == NULL || es->bottom == es->top) |
117 | 0 | return; |
118 | | |
119 | 0 | thread_es = ossl_err_get_state_int(); |
120 | 0 | if (thread_es == NULL) |
121 | 0 | return; |
122 | | |
123 | 0 | for (i = (size_t)es->bottom; i != (size_t)es->top;) { |
124 | 0 | size_t top; |
125 | |
|
126 | 0 | i = (i + 1) % ERR_NUM_ERRORS; |
127 | 0 | if ((es->err_flags[i] & ERR_FLAG_CLEAR) != 0) |
128 | 0 | continue; |
129 | | |
130 | 0 | err_get_slot(thread_es); |
131 | 0 | top = thread_es->top; |
132 | 0 | err_clear(thread_es, top, 0); |
133 | |
|
134 | 0 | thread_es->err_flags[top] = es->err_flags[i]; |
135 | 0 | thread_es->err_buffer[top] = es->err_buffer[i]; |
136 | |
|
137 | 0 | err_set_debug(thread_es, top, es->err_file[i], es->err_line[i], |
138 | 0 | es->err_func[i]); |
139 | |
|
140 | 0 | if (es->err_data[i] != NULL && es->err_data_size[i] != 0) { |
141 | 0 | void *data; |
142 | 0 | size_t data_sz = es->err_data_size[i]; |
143 | |
|
144 | 0 | data = CRYPTO_malloc(data_sz, NULL, 0); |
145 | 0 | if (data != NULL) { |
146 | 0 | memcpy(data, es->err_data[i], data_sz); |
147 | 0 | err_set_data(thread_es, top, data, data_sz, |
148 | 0 | es->err_data_flags[i] | ERR_TXT_MALLOCED); |
149 | 0 | } |
150 | 0 | } else { |
151 | 0 | err_clear_data(thread_es, top, 0); |
152 | 0 | } |
153 | 0 | } |
154 | 0 | } |