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-Tag: openssl-3.2.6~64 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f015c74c56f818d0bdf1e721e2ebec1345f9a232;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: Matt Caswell Reviewed-by: Neil Horman Reviewed-by: Saša Nedvědický (Merged from https://github.com/openssl/openssl/pull/28197) --- diff --git a/crypto/sleep.c b/crypto/sleep.c index dc97d4edc05..e327dd052f6 100644 --- a/crypto/sleep.c +++ b/crypto/sleep.c @@ -9,12 +9,14 @@ #include #include "internal/e_os.h" +#include "internal/time.h" /* system-specific variants defining OSSL_sleep() */ -#if defined(OPENSSL_SYS_UNIX) || defined(__DJGPP__) -#include +#if (defined(OPENSSL_SYS_UNIX) || defined(__DJGPP__)) \ + && !defined(OPENSSL_USE_SLEEP_BUSYLOOP) +# include -void OSSL_sleep(uint64_t millis) +static void ossl_sleep_millis(uint64_t millis) { # ifdef OPENSSL_SYS_VXWORKS struct timespec ts; @@ -38,7 +40,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 @@ -53,7 +55,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) { @@ -77,10 +79,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 dd19bfbc71d..05e395d4f35 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,77 @@ 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 itimerval it = { { 0, 111111 } }; + struct sigaction sa; + sigset_t mask; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = alrm_handler; + + 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 { + static const struct itimerval it = { { 0 } }; - if (!TEST_uint64_t_ge(seconds, 1) || !TEST_uint64_t_le(seconds, 20)) - return 0; + if (setitimer(ITIMER_REAL, &it, NULL)) { + TEST_perror("test_sanity_sleep: disarm setitimer"); + break; + } + } while (0); +#endif /* defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L */ + + 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 +217,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; }