xref: /openssl/test/errtest.c (revision d3bb8fe7)
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     const char *f, *data;
145     int l;
146     unsigned long e;
147 
148     /*
149      * When OPENSSL_NO_ERR or OPENSSL_NO_FILENAMES, no file name or line
150      * number is saved, so no point checking them.
151      */
152 #if !defined(OPENSSL_NO_FILENAMES) && !defined(OPENSSL_NO_ERR)
153     const char *file;
154     int line;
155 
156     file = __FILE__;
157     line = __LINE__ + 2; /* The error is generated on the ERR_raise_data line */
158 #endif
159     ERR_raise_data(ERR_LIB_NONE, ERR_R_INTERNAL_ERROR,
160                    "calling exit()");
161     if (!TEST_ulong_ne(e = ERR_get_error_all(&f, &l, NULL, &data, NULL), 0)
162             || !TEST_int_eq(ERR_GET_REASON(e), ERR_R_INTERNAL_ERROR)
163 #if !defined(OPENSSL_NO_FILENAMES) && !defined(OPENSSL_NO_ERR)
164             || !TEST_int_eq(l, line)
165             || !TEST_str_eq(f, file)
166 #endif
167             || !TEST_str_eq(data, "calling exit()"))
168         return 0;
169     return 1;
170 }
171 
test_marks(void)172 static int test_marks(void)
173 {
174     unsigned long mallocfail, shouldnot;
175 
176     /* Set an initial error */
177     ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
178     mallocfail = ERR_peek_last_error();
179     if (!TEST_ulong_gt(mallocfail, 0))
180         return 0;
181 
182     /* Setting and clearing a mark should not affect the error */
183     if (!TEST_true(ERR_set_mark())
184             || !TEST_true(ERR_pop_to_mark())
185             || !TEST_ulong_eq(mallocfail, ERR_peek_last_error())
186             || !TEST_true(ERR_set_mark())
187             || !TEST_true(ERR_clear_last_mark())
188             || !TEST_ulong_eq(mallocfail, ERR_peek_last_error()))
189         return 0;
190 
191     /* Test popping errors */
192     if (!TEST_true(ERR_set_mark()))
193         return 0;
194     ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
195     if (!TEST_ulong_ne(mallocfail, ERR_peek_last_error())
196             || !TEST_true(ERR_pop_to_mark())
197             || !TEST_ulong_eq(mallocfail, ERR_peek_last_error()))
198         return 0;
199 
200     /* Nested marks should also work */
201     if (!TEST_true(ERR_set_mark())
202             || !TEST_true(ERR_set_mark()))
203         return 0;
204     ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
205     if (!TEST_ulong_ne(mallocfail, ERR_peek_last_error())
206             || !TEST_true(ERR_pop_to_mark())
207             || !TEST_true(ERR_pop_to_mark())
208             || !TEST_ulong_eq(mallocfail, ERR_peek_last_error()))
209         return 0;
210 
211     if (!TEST_true(ERR_set_mark()))
212         return 0;
213     ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
214     shouldnot = ERR_peek_last_error();
215     if (!TEST_ulong_ne(mallocfail, shouldnot)
216             || !TEST_true(ERR_set_mark()))
217         return 0;
218     ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
219     if (!TEST_ulong_ne(shouldnot, ERR_peek_last_error())
220             || !TEST_true(ERR_pop_to_mark())
221             || !TEST_ulong_eq(shouldnot, ERR_peek_last_error())
222             || !TEST_true(ERR_pop_to_mark())
223             || !TEST_ulong_eq(mallocfail, ERR_peek_last_error()))
224         return 0;
225 
226     /* Setting and clearing a mark should not affect the errors on the stack */
227     if (!TEST_true(ERR_set_mark()))
228         return 0;
229     ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
230     if (!TEST_true(ERR_clear_last_mark())
231             || !TEST_ulong_eq(shouldnot, ERR_peek_last_error()))
232         return 0;
233 
234     /*
235      * Popping where no mark has been set should pop everything - but return
236      * a failure result
237      */
238     if (!TEST_false(ERR_pop_to_mark())
239             || !TEST_ulong_eq(0, ERR_peek_last_error()))
240         return 0;
241 
242     /* Clearing where there is no mark should fail */
243     ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
244     if (!TEST_false(ERR_clear_last_mark())
245                 /* "get" the last error to remove it */
246             || !TEST_ulong_eq(mallocfail, ERR_get_error())
247             || !TEST_ulong_eq(0, ERR_peek_last_error()))
248         return 0;
249 
250     /*
251      * Setting a mark where there are no errors in the stack should fail.
252      * NOTE: This is somewhat surprising behaviour but is historically how this
253      * function behaves. In practice we typically set marks without first
254      * checking whether there is anything on the stack - but we also don't
255      * tend to check the success of this function. It turns out to work anyway
256      * because although setting a mark with no errors fails, a subsequent call
257      * to ERR_pop_to_mark() or ERR_clear_last_mark() will do the right thing
258      * anyway (even though they will report a failure result).
259      */
260     if (!TEST_false(ERR_set_mark()))
261         return 0;
262 
263     ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
264     if (!TEST_true(ERR_set_mark()))
265         return 0;
266     ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
267     ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
268 
269     /* Should be able to "pop" past 2 errors */
270     if (!TEST_true(ERR_pop_to_mark())
271             || !TEST_ulong_eq(mallocfail, ERR_peek_last_error()))
272         return 0;
273 
274     if (!TEST_true(ERR_set_mark()))
275         return 0;
276     ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR);
277     ERR_raise(ERR_LIB_CRYPTO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
278 
279     /* Should be able to "clear" past 2 errors */
280     if (!TEST_true(ERR_clear_last_mark())
281             || !TEST_ulong_eq(shouldnot, ERR_peek_last_error()))
282         return 0;
283 
284     /* Clear remaining errors from last test */
285     ERR_clear_error();
286 
287     return 1;
288 }
289 
test_clear_error(void)290 static int test_clear_error(void)
291 {
292     int flags = -1;
293     const char *data = NULL;
294     int res = 0;
295 
296     /* Raise an error with data and clear it */
297     ERR_raise_data(0, 0, "hello %s", "world");
298     ERR_peek_error_data(&data, &flags);
299     if (!TEST_str_eq(data, "hello world")
300             || !TEST_int_eq(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED))
301         goto err;
302     ERR_clear_error();
303 
304     /* Raise a new error without data */
305     ERR_raise(0, 0);
306     ERR_peek_error_data(&data, &flags);
307     if (!TEST_str_eq(data, "")
308             || !TEST_int_eq(flags, ERR_TXT_MALLOCED))
309         goto err;
310     ERR_clear_error();
311 
312     /* Raise a new error with data */
313     ERR_raise_data(0, 0, "goodbye %s world", "cruel");
314     ERR_peek_error_data(&data, &flags);
315     if (!TEST_str_eq(data, "goodbye cruel world")
316             || !TEST_int_eq(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED))
317         goto err;
318     ERR_clear_error();
319 
320     /*
321      * Raise a new error without data to check that the malloced storage
322      * is freed properly
323      */
324     ERR_raise(0, 0);
325     ERR_peek_error_data(&data, &flags);
326     if (!TEST_str_eq(data, "")
327             || !TEST_int_eq(flags, ERR_TXT_MALLOCED))
328         goto err;
329     ERR_clear_error();
330 
331     res = 1;
332  err:
333      ERR_clear_error();
334     return res;
335 }
336 
337 /*
338  * Test saving and restoring error state.
339  * Test 0: Save using OSSL_ERR_STATE_save()
340  * Test 1: Save using OSSL_ERR_STATE_save_to_mark()
341  */
test_save_restore(int idx)342 static int test_save_restore(int idx)
343 {
344     ERR_STATE *es;
345     int res = 0, i, flags = -1;
346     unsigned long mallocfail, interr;
347     static const char testdata[] = "test data";
348     const char *data = NULL;
349 
350     if (!TEST_ptr(es = OSSL_ERR_STATE_new()))
351         goto err;
352 
353     ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE);
354     mallocfail = ERR_peek_last_error();
355     if (!TEST_ulong_gt(mallocfail, 0))
356         goto err;
357 
358     if (idx == 1 && !TEST_int_eq(ERR_set_mark(), 1))
359         goto err;
360 
361     ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR, testdata);
362     interr = ERR_peek_last_error();
363     if (!TEST_ulong_ne(mallocfail, ERR_peek_last_error()))
364         goto err;
365 
366     if (idx == 0) {
367         OSSL_ERR_STATE_save(es);
368 
369         if (!TEST_ulong_eq(ERR_peek_last_error(), 0))
370             goto err;
371     } else {
372         OSSL_ERR_STATE_save_to_mark(es);
373 
374         if (!TEST_ulong_ne(ERR_peek_last_error(), 0))
375             goto err;
376     }
377 
378     for (i = 0; i < 2; i++) {
379         OSSL_ERR_STATE_restore(es);
380 
381         if (!TEST_ulong_eq(ERR_peek_last_error(), interr))
382             goto err;
383         ERR_peek_last_error_data(&data, &flags);
384         if (!TEST_str_eq(data, testdata)
385                 || !TEST_int_eq(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED))
386             goto err;
387 
388         /* restore again to duplicate the entries */
389         OSSL_ERR_STATE_restore(es);
390 
391         /* verify them all */
392         if (idx == 0 || i == 0) {
393             if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL,
394                                                  &data, &flags), mallocfail)
395                 || !TEST_int_ne(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED))
396                 goto err;
397         }
398 
399         if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL,
400                                              &data, &flags), interr)
401             || !TEST_str_eq(data, testdata)
402             || !TEST_int_eq(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED))
403             goto err;
404 
405         if (idx == 0) {
406             if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL,
407                                                  &data, &flags), mallocfail)
408                 || !TEST_int_ne(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED))
409                 goto err;
410         }
411 
412         if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL,
413                                              &data, &flags), interr)
414             || !TEST_str_eq(data, testdata)
415             || !TEST_int_eq(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED))
416             goto err;
417 
418         if (!TEST_ulong_eq(ERR_get_error(), 0))
419             goto err;
420     }
421 
422     res = 1;
423  err:
424     OSSL_ERR_STATE_free(es);
425     return res;
426 }
427 
setup_tests(void)428 int setup_tests(void)
429 {
430     ADD_TEST(preserves_system_error);
431     ADD_TEST(vdata_appends);
432     ADD_TEST(raised_error);
433 #ifndef OPENSSL_NO_DEPRECATED_3_0
434     ADD_TEST(test_print_error_format);
435 #endif
436     ADD_TEST(test_marks);
437     ADD_ALL_TESTS(test_save_restore, 2);
438     ADD_TEST(test_clear_error);
439     return 1;
440 }
441