From: David Benjamin Date: Sun, 20 May 2018 21:24:30 +0000 (-0400) Subject: Save and restore the Windows error around TlsGetValue. X-Git-Tag: OpenSSL_1_1_0i~100 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=1ae891c6b15e28b280845858326fb50ea5b61ac7;p=oweals%2Fopenssl.git Save and restore the Windows error around TlsGetValue. TlsGetValue clears the last error even on success, so that callers may distinguish it successfully returning NULL or failing. This error-mangling behavior interferes with the caller's use of GetLastError. In particular SSL_get_error queries the error queue to determine whether the caller should look at the OS's errors. To avoid destroying state, save and restore the Windows error. Fixes #6299. Reviewed-by: Rich Salz (cherry picked from commit 2de108dfa343c3e06eb98beb122cd06306bb12fd) (Merged from https://github.com/openssl/openssl/pull/6349) --- diff --git a/crypto/threads_win.c b/crypto/threads_win.c index 4e0de908ee..c9da56b565 100644 --- a/crypto/threads_win.c +++ b/crypto/threads_win.c @@ -98,7 +98,26 @@ int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *)) void *CRYPTO_THREAD_get_local(CRYPTO_THREAD_LOCAL *key) { - return TlsGetValue(*key); + DWORD last_error; + void *ret; + + /* + * TlsGetValue clears the last error even on success, so that callers may + * distinguish it successfully returning NULL or failing. It is documented + * to never fail if the argument is a valid index from TlsAlloc, so we do + * not need to handle this. + * + * However, this error-mangling behavior interferes with the caller's use of + * GetLastError. In particular SSL_get_error queries the error queue to + * determine whether the caller should look at the OS's errors. To avoid + * destroying state, save and restore the Windows error. + * + * https://msdn.microsoft.com/en-us/library/windows/desktop/ms686812(v=vs.85).aspx + */ + last_error = GetLastError(); + ret = TlsGetValue(*key); + SetLastError(last_error); + return ret; } int CRYPTO_THREAD_set_local(CRYPTO_THREAD_LOCAL *key, void *val) diff --git a/test/build.info b/test/build.info index dcb398517c..87961bc834 100644 --- a/test/build.info +++ b/test/build.info @@ -18,7 +18,7 @@ IF[{- !$disabled{tests} -}] dtlsv1listentest ct_test threadstest afalgtest d2i_test \ ssl_test_ctx_test ssl_test x509aux cipherlist_test asynciotest \ bioprinttest sslapitest dtlstest sslcorrupttest bio_enc_test \ - ocspapitest fatalerrtest x509_time_test + ocspapitest fatalerrtest x509_time_test errtest SOURCE[versions]=versions.c INCLUDE[versions]=../include @@ -306,6 +306,10 @@ IF[{- !$disabled{tests} -}] SOURCE[shlibloadtest]=shlibloadtest.c INCLUDE[shlibloadtest]=../include ENDIF + + SOURCE[errtest]=errtest.c testutil.c + INCLUDE[errtest]=../include + DEPEND[errtest]=../libcrypto ENDIF {- diff --git a/test/errtest.c b/test/errtest.c new file mode 100644 index 0000000000..df4cddb096 --- /dev/null +++ b/test/errtest.c @@ -0,0 +1,40 @@ +/* + * Copyright 2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include + +#include "testutil.h" + +#if defined(OPENSSL_SYS_WINDOWS) +# include +#else +# include +#endif + +/* Test that querying the error queue preserves the OS error. */ +static int preserves_system_error(void) +{ +#if defined(OPENSSL_SYS_WINDOWS) + SetLastError(ERROR_INVALID_FUNCTION); + ERR_get_error(); + return GetLastError() == ERROR_INVALID_FUNCTION; +#else + errno = EINVAL; + ERR_get_error(); + return errno == EINVAL; +#endif +} + +int main(int argc, char **argv) +{ + ADD_TEST(preserves_system_error); + + return run_tests(argv[0]); +} diff --git a/test/recipes/04-test_err.t b/test/recipes/04-test_err.t new file mode 100644 index 0000000000..dd7681afa4 --- /dev/null +++ b/test/recipes/04-test_err.t @@ -0,0 +1,12 @@ +#! /usr/bin/env perl +# Copyright 2018 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the OpenSSL license (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + + +use OpenSSL::Test::Simple; + +simple_test("test_err", "errtest");