]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
crypto/sleep.c: avoid returning early due to signal master
authorEugene Syromiatnikov <esyr@openssl.org>
Thu, 7 Aug 2025 14:01:23 +0000 (16:01 +0200)
committerNeil Horman <nhorman@openssl.org>
Sat, 9 Aug 2025 19:33:08 +0000 (15:33 -0400)
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 <esyr@redhat.com>
Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Saša Nedvědický <sashan@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/28193)

crypto/sleep.c
test/sanitytest.c

index dbd0f7802576b7942f4fd81c5d3e908e0bb3287b..65c799e574c5ac97cb92fd45f3803214a6637ae1 100644 (file)
@@ -9,9 +9,10 @@
 
 #include <openssl/crypto.h>
 #include "internal/e_os.h"
 
 #include <openssl/crypto.h>
 #include "internal/e_os.h"
+#include "internal/time.h"
 
 /* system-specific variants defining OSSL_sleep() */
 
 /* 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__)                               \
 
 # if defined(OPENSSL_USE_USLEEP)                        \
     || defined(__DJGPP__)                               \
@@ -26,7 +27,7 @@
  */
 
 #  include <unistd.h>
  */
 
 #  include <unistd.h>
-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);
 {
     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 <cextdecs.h(PROCESS_DELAY_)>
 # elif defined(__TANDEM) && !defined(_REENTRANT)
 
 #  include <cextdecs.h(PROCESS_DELAY_)>
-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);
 {
     /* 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 <time.h>
 
 /* nanosleep is defined by POSIX.1-2001 */
 #  include <time.h>
-void OSSL_sleep(uint64_t millis)
+static void ossl_sleep_millis(uint64_t millis)
 {
     struct timespec ts;
 
 {
     struct timespec ts;
 
@@ -68,7 +69,7 @@ void OSSL_sleep(uint64_t millis)
 #elif defined(_WIN32) && !defined(OPENSSL_SYS_UEFI)
 # include <windows.h>
 
 #elif defined(_WIN32) && !defined(OPENSSL_SYS_UEFI)
 # include <windows.h>
 
-void OSSL_sleep(uint64_t millis)
+static void ossl_sleep_millis(uint64_t millis)
 {
     /*
      * Windows' Sleep() takes a DWORD argument, which is smaller than
 {
     /*
      * 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 */
 
 #else
 /* Fallback to a busy wait */
-# include "internal/time.h"
+# define USE_SLEEP_SECS
 
 static void ossl_sleep_secs(uint64_t 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 */ ;
 }
     while (ossl_time_compare(ossl_time_now(), finish) < 0)
         /* busy wait */ ;
 }
+#endif /* defined(OPENSSL_SYS_UNIX) || defined(__DJGPP__) */
 
 void OSSL_sleep(uint64_t millis)
 {
 
 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__) */
index dd19bfbc71da0ebc6262b1f5d487aead4aad0d79..2dab0340dee5698d8ef63f4be253916f733c6cb9 100644 (file)
 #include "internal/numbers.h"
 #include "internal/time.h"
 
 #include "internal/numbers.h"
 #include "internal/time.h"
 
+#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L
+# include <signal.h>
+#endif
+
 static int test_sanity_null_zero(void)
 {
     char *p;
 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);
 }
 
     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();
     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;
 }
 
     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_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;
 }
     return 1;
 }