1 /*
2 * Copyright 2018-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 #include <string.h>
11 #include <openssl/opensslconf.h>
12 #include <openssl/err.h>
13 #include <openssl/macros.h>
14
15 #include "testutil.h"
16
17 #if defined(OPENSSL_SYS_WINDOWS)
18 #include <windows.h>
19 #else
20 #include <errno.h>
21 #endif
22
23 #ifndef OPENSSL_NO_DEPRECATED_3_0
24 #define IS_HEX(ch) ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F'))
25
test_print_error_format(void)26 static int test_print_error_format(void)
27 {
28 /* Variables used to construct an error line */
29 char *lib;
30 const char *func = OPENSSL_FUNC;
31 char *reason;
32 #ifdef OPENSSL_NO_ERR
33 char reasonbuf[255];
34 #endif
35 #ifndef OPENSSL_NO_FILENAMES
36 const char *file = OPENSSL_FILE;
37 const int line = OPENSSL_LINE;
38 #else
39 const char *file = "";
40 const int line = 0;
41 #endif
42 /* The format for OpenSSL error lines */
43 const char *expected_format = ":error:%08lX:%s:%s:%s:%s:%d";
44 /*-
45 * ^^ ^^ ^^ ^^ ^^
46 * "library" name --------------------------++ || || || ||
47 * function name ------------------------------++ || || ||
48 * reason string (system error string) -----------++ || ||
49 * file name ----------------------------------------++ ||
50 * line number -----------------------------------------++
51 */
52 char expected[512];
53
54 char *out = NULL, *p = NULL;
55 int ret = 0, len;
56 BIO *bio = NULL;
57 const int syserr = EPERM;
58 unsigned long errorcode;
59 unsigned long reasoncode;
60
61 /*
62 * We set a mark here so we can clear the system error that we generate
63 * with ERR_PUT_error(). That is, after all, just a simulation to verify
64 * ERR_print_errors() output, not a real error.
65 */
66 ERR_set_mark();
67
68 ERR_PUT_error(ERR_LIB_SYS, 0, syserr, file, line);
69 errorcode = ERR_peek_error();
70 reasoncode = ERR_GET_REASON(errorcode);
71
72 if (!TEST_int_eq(reasoncode, syserr)) {
73 ERR_pop_to_mark();
74 goto err;
75 }
76
77 #if !defined(OPENSSL_NO_ERR)
78 #if defined(OPENSSL_NO_AUTOERRINIT)
79 lib = "lib(2)";
80 #else
81 lib = "system library";
82 #endif
83 reason = strerror(syserr);
84 #else
85 lib = "lib(2)";
86 BIO_snprintf(reasonbuf, sizeof(reasonbuf), "reason(%lu)", reasoncode);
87 reason = reasonbuf;
88 #endif
89
90 BIO_snprintf(expected, sizeof(expected), expected_format,
91 errorcode, lib, func, reason, file, line);
92
93 if (!TEST_ptr(bio = BIO_new(BIO_s_mem())))
94 goto err;
95
96 ERR_print_errors(bio);
97
98 if (!TEST_int_gt(len = BIO_get_mem_data(bio, &out), 0))
99 goto err;
100 /* Skip over the variable thread id at the start of the string */
101 for (p = out; *p != ':' && *p != 0; ++p) {
102 if (!TEST_true(IS_HEX(*p)))
103 goto err;
104 }
105 if (!TEST_true(*p != 0)
106 || !TEST_strn_eq(expected, p, strlen(expected)))
107 goto err;
108
109 ret = 1;
110 err:
111 BIO_free(bio);
112 return ret;
113 }
114 #endif
115
116 /* Test that querying the error queue preserves the OS error. */
preserves_system_error(void)117 static int preserves_system_error(void)
118 {
119 #if defined(OPENSSL_SYS_WINDOWS)
120 SetLastError(ERROR_INVALID_FUNCTION);
121 ERR_get_error();
122 return TEST_int_eq(GetLastError(), ERROR_INVALID_FUNCTION);
123 #else
124 errno = EINVAL;
125 ERR_get_error();
126 return TEST_int_eq(errno, EINVAL);
127 #endif
128 }
129
130 /* Test that calls to ERR_add_error_[v]data append */
vdata_appends(void)131 static int vdata_appends(void)
132 {
133 const char *data;
134
135 ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
136 ERR_add_error_data(1, "hello ");
137 ERR_add_error_data(1, "world");
138 ERR_peek_error_data(&data, NULL);
139 return TEST_str_eq(data, "hello world");
140 }
141
raised_error(void)142 static int raised_error(void)
143 {
144 int l, start_line = -1, end_line = -1;
145 const char *f, *data, *file = NULL;
146 unsigned long e;
147
148 file = __FILE__;
149
150 start_line = __LINE__ + 1;
151 ERR_raise_data(ERR_LIB_NONE, ERR_R_INTERNAL_ERROR,
152 "calling exit()");
153 end_line = __LINE__ - 1;
154 if (!TEST_ulong_ne(e = ERR_get_error_all(&f, &l, NULL, &data, NULL), 0)
155 || !TEST_int_eq(ERR_GET_REASON(e), ERR_R_INTERNAL_ERROR)
156 || (l > 0 && !(TEST_int_eq(l, start_line) || TEST_int_eq(l, end_line)))
157 || (strlen(f) != 0 && !TEST_str_eq(f, file))
158 || !TEST_str_eq(data, "calling exit()"))
159 return 0;
160 return 1;
161 }
162
test_marks(void)163 static int test_marks(void)
164 {
165 unsigned long mallocfail, shouldnot;
166
167 /* Set an initial error */
168 ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
169 mallocfail = ERR_peek_last_error();
170 if (!TEST_ulong_gt(mallocfail, 0))
171 return 0;
172
173 /* Setting and clearing a mark should not affect the error */
174 if (!TEST_true(ERR_set_mark())
175 || !TEST_true(ERR_pop_to_mark())
176 || !TEST_ulong_eq(mallocfail, ERR_peek_last_error())
177 || !TEST_true(ERR_set_mark())
178 || !TEST_true(ERR_clear_last_mark())
179 || !TEST_ulong_eq(mallocfail, ERR_peek_last_error()))
180 return 0;
181
182 /* Test popping errors */
183 if (!TEST_true(ERR_set_mark()))
184 return 0;
185 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
186 if (!TEST_ulong_ne(mallocfail, ERR_peek_last_error())
187 || !TEST_true(ERR_pop_to_mark())
188 || !TEST_ulong_eq(mallocfail, ERR_peek_last_error()))
189 return 0;
190
191 /* Nested marks should also work */
192 if (!TEST_true(ERR_set_mark())
193 || !TEST_true(ERR_set_mark()))
194 return 0;
195 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
196 if (!TEST_ulong_ne(mallocfail, ERR_peek_last_error())
197 || !TEST_true(ERR_pop_to_mark())
198 || !TEST_true(ERR_pop_to_mark())
199 || !TEST_ulong_eq(mallocfail, ERR_peek_last_error()))
200 return 0;
201
202 if (!TEST_true(ERR_set_mark()))
203 return 0;
204 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
205 shouldnot = ERR_peek_last_error();
206 if (!TEST_ulong_ne(mallocfail, shouldnot)
207 || !TEST_true(ERR_set_mark()))
208 return 0;
209 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
210 if (!TEST_ulong_ne(shouldnot, ERR_peek_last_error())
211 || !TEST_true(ERR_pop_to_mark())
212 || !TEST_ulong_eq(shouldnot, ERR_peek_last_error())
213 || !TEST_true(ERR_pop_to_mark())
214 || !TEST_ulong_eq(mallocfail, ERR_peek_last_error()))
215 return 0;
216
217 /* Setting and clearing a mark should not affect the errors on the stack */
218 if (!TEST_true(ERR_set_mark()))
219 return 0;
220 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
221 if (!TEST_true(ERR_clear_last_mark())
222 || !TEST_ulong_eq(shouldnot, ERR_peek_last_error()))
223 return 0;
224
225 /*
226 * Popping where no mark has been set should pop everything - but return
227 * a failure result
228 */
229 if (!TEST_false(ERR_pop_to_mark())
230 || !TEST_ulong_eq(0, ERR_peek_last_error()))
231 return 0;
232
233 /* Clearing where there is no mark should fail */
234 ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
235 if (!TEST_false(ERR_clear_last_mark())
236 /* "get" the last error to remove it */
237 || !TEST_ulong_eq(mallocfail, ERR_get_error())
238 || !TEST_ulong_eq(0, ERR_peek_last_error()))
239 return 0;
240
241 /*
242 * Setting a mark where there are no errors in the stack should fail.
243 * NOTE: This is somewhat surprising behaviour but is historically how this
244 * function behaves. In practice we typically set marks without first
245 * checking whether there is anything on the stack - but we also don't
246 * tend to check the success of this function. It turns out to work anyway
247 * because although setting a mark with no errors fails, a subsequent call
248 * to ERR_pop_to_mark() or ERR_clear_last_mark() will do the right thing
249 * anyway (even though they will report a failure result).
250 */
251 if (!TEST_false(ERR_set_mark()))
252 return 0;
253
254 ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
255 if (!TEST_true(ERR_set_mark()))
256 return 0;
257 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
258 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
259
260 /* Should be able to "pop" past 2 errors */
261 if (!TEST_true(ERR_pop_to_mark())
262 || !TEST_ulong_eq(mallocfail, ERR_peek_last_error()))
263 return 0;
264
265 if (!TEST_true(ERR_set_mark()))
266 return 0;
267 ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
268 ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
269
270 /* Should be able to "clear" past 2 errors */
271 if (!TEST_true(ERR_clear_last_mark())
272 || !TEST_ulong_eq(shouldnot, ERR_peek_last_error()))
273 return 0;
274
275 /* Clear remaining errors from last test */
276 ERR_clear_error();
277
278 return 1;
279 }
280
test_clear_error(void)281 static int test_clear_error(void)
282 {
283 int flags = -1;
284 const char *data = NULL;
285 int res = 0;
286
287 /* Raise an error with data and clear it */
288 ERR_raise_data(0, 0, "hello %s", "world");
289 ERR_peek_error_data(&data, &flags);
290 if (!TEST_str_eq(data, "hello world")
291 || !TEST_int_eq(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED))
292 goto err;
293 ERR_clear_error();
294
295 /* Raise a new error without data */
296 ERR_raise(0, 0);
297 ERR_peek_error_data(&data, &flags);
298 if (!TEST_str_eq(data, "")
299 || !TEST_int_eq(flags, ERR_TXT_MALLOCED))
300 goto err;
301 ERR_clear_error();
302
303 /* Raise a new error with data */
304 ERR_raise_data(0, 0, "goodbye %s world", "cruel");
305 ERR_peek_error_data(&data, &flags);
306 if (!TEST_str_eq(data, "goodbye cruel world")
307 || !TEST_int_eq(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED))
308 goto err;
309 ERR_clear_error();
310
311 /*
312 * Raise a new error without data to check that the malloced storage
313 * is freed properly
314 */
315 ERR_raise(0, 0);
316 ERR_peek_error_data(&data, &flags);
317 if (!TEST_str_eq(data, "")
318 || !TEST_int_eq(flags, ERR_TXT_MALLOCED))
319 goto err;
320 ERR_clear_error();
321
322 res = 1;
323 err:
324 ERR_clear_error();
325 return res;
326 }
327
328 /*
329 * Test saving and restoring error state.
330 * Test 0: Save using OSSL_ERR_STATE_save()
331 * Test 1: Save using OSSL_ERR_STATE_save_to_mark()
332 */
test_save_restore(int idx)333 static int test_save_restore(int idx)
334 {
335 ERR_STATE *es;
336 int res = 0, i, flags = -1;
337 unsigned long mallocfail, interr;
338 static const char testdata[] = "test data";
339 const char *data = NULL;
340
341 if (!TEST_ptr(es = OSSL_ERR_STATE_new()))
342 goto err;
343
344 ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
345 mallocfail = ERR_peek_last_error();
346 if (!TEST_ulong_gt(mallocfail, 0))
347 goto err;
348
349 if (idx == 1 && !TEST_int_eq(ERR_set_mark(), 1))
350 goto err;
351
352 ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR, testdata);
353 interr = ERR_peek_last_error();
354 if (!TEST_ulong_ne(mallocfail, ERR_peek_last_error()))
355 goto err;
356
357 if (idx == 0) {
358 OSSL_ERR_STATE_save(es);
359
360 if (!TEST_ulong_eq(ERR_peek_last_error(), 0))
361 goto err;
362 } else {
363 OSSL_ERR_STATE_save_to_mark(es);
364
365 if (!TEST_ulong_ne(ERR_peek_last_error(), 0))
366 goto err;
367 }
368
369 for (i = 0; i < 2; i++) {
370 OSSL_ERR_STATE_restore(es);
371
372 if (!TEST_ulong_eq(ERR_peek_last_error(), interr))
373 goto err;
374 ERR_peek_last_error_data(&data, &flags);
375 if (!TEST_str_eq(data, testdata)
376 || !TEST_int_eq(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED))
377 goto err;
378
379 /* restore again to duplicate the entries */
380 OSSL_ERR_STATE_restore(es);
381
382 /* verify them all */
383 if (idx == 0 || i == 0) {
384 if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL,
385 &data, &flags),
386 mallocfail)
387 || !TEST_int_ne(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED))
388 goto err;
389 }
390
391 if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL,
392 &data, &flags),
393 interr)
394 || !TEST_str_eq(data, testdata)
395 || !TEST_int_eq(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED))
396 goto err;
397
398 if (idx == 0) {
399 if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL,
400 &data, &flags),
401 mallocfail)
402 || !TEST_int_ne(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED))
403 goto err;
404 }
405
406 if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL,
407 &data, &flags),
408 interr)
409 || !TEST_str_eq(data, testdata)
410 || !TEST_int_eq(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED))
411 goto err;
412
413 if (!TEST_ulong_eq(ERR_get_error(), 0))
414 goto err;
415 }
416
417 res = 1;
418 err:
419 OSSL_ERR_STATE_free(es);
420 return res;
421 }
422
setup_tests(void)423 int setup_tests(void)
424 {
425 ADD_TEST(preserves_system_error);
426 ADD_TEST(vdata_appends);
427 ADD_TEST(raised_error);
428 #ifndef OPENSSL_NO_DEPRECATED_3_0
429 ADD_TEST(test_print_error_format);
430 #endif
431 ADD_TEST(test_marks);
432 ADD_ALL_TESTS(test_save_restore, 2);
433 ADD_TEST(test_clear_error);
434 return 1;
435 }
436