xref: /freebsd/crypto/openssl/test/errtest.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
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