From: Eugene Syromiatnikov Date: Thu, 7 Aug 2025 14:01:23 +0000 (+0200) Subject: crypto/sleep.c: avoid returning early due to signal X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;p=thirdparty%2Fopenssl.git crypto/sleep.c: avoid returning early due to signal On POSIX systems, sleep/usleep/nanosleep may return early due to arrival of a signal, and OSSL_sleep does not report that, so it is assumed that it cannot return early. Fix that by introducing a loop that checks the remaining time and sleep some more if the time has not passed; that also solves the issue of limited sleeping time on some systems. Signed-off-by: Eugene Syromiatnikov Reviewed-by: Neil Horman Reviewed-by: Saša Nedvědický Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/28193) --- diff --git a/crypto/sleep.c b/crypto/sleep.c index dbd0f78025..65c799e574 100644 --- a/crypto/sleep.c +++ b/crypto/sleep.c @@ -9,9 +9,10 @@ #include #include "internal/e_os.h" +#include "internal/time.h" /* system-specific variants defining OSSL_sleep() */ -#if defined(OPENSSL_SYS_UNIX) || defined(__DJGPP__) +#if (defined(OPENSSL_SYS_UNIX) || defined(__DJGPP__)) && !defined(OPENSSL_USE_SLEEP_BUSYLOOP) # if defined(OPENSSL_USE_USLEEP) \ || defined(__DJGPP__) \ @@ -26,7 +27,7 @@ */ # include -void OSSL_sleep(uint64_t millis) +static void ossl_sleep_millis(uint64_t millis) { unsigned int s = (unsigned int)(millis / 1000); unsigned int us = (unsigned int)((millis % 1000) * 1000); @@ -45,7 +46,7 @@ void OSSL_sleep(uint64_t millis) # elif defined(__TANDEM) && !defined(_REENTRANT) # include -void OSSL_sleep(uint64_t millis) +static void ossl_sleep_millis(uint64_t millis) { /* HPNS does not support usleep for non threaded apps */ PROCESS_DELAY_(millis * 1000); @@ -55,7 +56,7 @@ void OSSL_sleep(uint64_t millis) /* nanosleep is defined by POSIX.1-2001 */ # include -void OSSL_sleep(uint64_t millis) +static void ossl_sleep_millis(uint64_t millis) { struct timespec ts; @@ -68,7 +69,7 @@ void OSSL_sleep(uint64_t millis) #elif defined(_WIN32) && !defined(OPENSSL_SYS_UEFI) # include -void OSSL_sleep(uint64_t millis) +static void ossl_sleep_millis(uint64_t millis) { /* * Windows' Sleep() takes a DWORD argument, which is smaller than @@ -83,7 +84,7 @@ void OSSL_sleep(uint64_t millis) #else /* Fallback to a busy wait */ -# include "internal/time.h" +# define USE_SLEEP_SECS static void ossl_sleep_secs(uint64_t secs) { @@ -107,10 +108,28 @@ static void ossl_sleep_millis(uint64_t millis) while (ossl_time_compare(ossl_time_now(), finish) < 0) /* busy wait */ ; } +#endif /* defined(OPENSSL_SYS_UNIX) || defined(__DJGPP__) */ void OSSL_sleep(uint64_t millis) { - ossl_sleep_secs(millis / 1000); - ossl_sleep_millis(millis % 1000); + OSSL_TIME now = ossl_time_now(); + OSSL_TIME finish = ossl_time_add(now, ossl_ms2time(millis)); + uint64_t left = millis; + +#if defined(USE_SLEEP_SECS) + do { + ossl_sleep_secs(left / 1000); + now = ossl_time_now(); + left = ossl_time2ms(ossl_time_subtract(finish, now)); + } while (ossl_time_compare(now, finish) < 0 && left > 1000); + + if (ossl_time_compare(now, finish) >= 0) + return; +#endif + + do { + ossl_sleep_millis(left); + now = ossl_time_now(); + left = ossl_time2ms(ossl_time_subtract(finish, now)); + } while (ossl_time_compare(now, finish) < 0); } -#endif /* defined(OPENSSL_SYS_UNIX) || defined(__DJGPP__) */ diff --git a/test/sanitytest.c b/test/sanitytest.c index dd19bfbc71..2dab0340de 100644 --- a/test/sanitytest.c +++ b/test/sanitytest.c @@ -13,6 +13,10 @@ #include "internal/numbers.h" #include "internal/time.h" +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L +# include +#endif + static int test_sanity_null_zero(void) { char *p; @@ -130,22 +134,72 @@ static int test_sanity_memcmp(void) return CRYPTO_memcmp("ab", "cd", 2); } -static int test_sanity_sleep(void) +static const struct sleep_test_vector { + uint64_t val; +} sleep_test_vectors[] = { { 0 }, { 1 }, { 999 }, { 1000 } }; + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L +static void +alrm_handler(int sig) +{ +} +#endif /* defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L */ + +static int test_sanity_sleep(int i) { + const struct sleep_test_vector * const td = sleep_test_vectors + i; OSSL_TIME start = ossl_time_now(); - uint64_t seconds; + uint64_t ms; +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L /* - * On any reasonable system this must sleep at least one second - * but not more than 20. - * Assuming there is no interruption. + * Set up an interrupt timer to check that OSSL_sleep doesn't return early + * due to interrupts. */ - OSSL_sleep(1000); + do { + static const struct sigaction sa = { .sa_handler = alrm_handler }; + static const struct itimerval it = { .it_value.tv_usec = 111111 }; + sigset_t mask; + + if (sigaction(SIGALRM, &sa, NULL)) { + TEST_perror("test_sanity_sleep: sigaction"); + break; + } + + sigemptyset(&mask); + sigaddset(&mask, SIGALRM); + if (sigprocmask(SIG_UNBLOCK, &mask, NULL)) { + TEST_perror("test_sanity_sleep: sigprocmask"); + break; + } + + if (setitimer(ITIMER_REAL, &it, NULL)) { + TEST_perror("test_sanity_sleep: arm setitimer"); + break; + } + } while (0); +#endif /* defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L */ - seconds = ossl_time2seconds(ossl_time_subtract(ossl_time_now(), start)); + /* + * On any reasonable system this must sleep at least the specified time + * but not more than 20 seconds more than that. + */ + OSSL_sleep(td->val); + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L + /* disarm the timer */ + do { + if (setitimer(ITIMER_REAL, NULL, NULL)) { + TEST_perror("test_sanity_sleep: disarm setitimer"); + break; + } + } while (0); +#endif /* defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L */ - if (!TEST_uint64_t_ge(seconds, 1) || !TEST_uint64_t_le(seconds, 20)) - return 0; + ms = ossl_time2ms(ossl_time_subtract(ossl_time_now(), start)); + + if (!TEST_uint64_t_ge(ms, td->val) + !TEST_uint64_t_le(ms, td->val + 20000)) + return 0; return 1; } @@ -158,6 +212,6 @@ int setup_tests(void) ADD_TEST(test_sanity_unsigned_conversion); ADD_TEST(test_sanity_range); ADD_TEST(test_sanity_memcmp); - ADD_TEST(test_sanity_sleep); + ADD_ALL_TESTS(test_sanity_sleep, OSSL_NELEM(sleep_test_vectors)); return 1; }