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 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. */ 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 */ 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 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 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 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 */ 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 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