1/*
2 * Copyright 2018-2021 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
26static 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;
110err:
111    BIO_free(bio);
112    return ret;
113}
114#endif
115
116/* Test that querying the error queue preserves the OS error. */
117static 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 */
131static 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
142static 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
172static 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
290static 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
337int setup_tests(void)
338{
339    ADD_TEST(preserves_system_error);
340    ADD_TEST(vdata_appends);
341    ADD_TEST(raised_error);
342#ifndef OPENSSL_NO_DEPRECATED_3_0
343    ADD_TEST(test_print_error_format);
344#endif
345    ADD_TEST(test_marks);
346    ADD_TEST(test_clear_error);
347    return 1;
348}
349