[LTP] [PATCH v2] openposix: timer_*/speculative: fork() to isolate the SIGSEGV on old glibc
Avinesh Kumar
avinesh.kumar@suse.com
Tue Sep 29 21:31:15 CEST 2026
From: Avinesh Kumar <avinesh.kumar@suse.com>
Commit d377d1cff1ec ("openposix: timer_*/speculative: Don't pass a
stack pointer as timerid") fixed a SIGSEGV on i586, where current
glibc's sign-bit check (timer_is_sigev_thread()) can misread a stack
address as a tagged pointer. A small constant avoids that.
But older glibc (<= 2.31, before this check existed) unconditionally
dereferences timerid as a pointer, so the same small constant now
faults instead:
timer_delete_sp[13131]: segfault at 186a3 ip 00007f15973aed4e sp 00007ffefb52c5a0 error 4 in librt-2.31.so[7f15973aa000+8000]
fork() a child to make the call, then inspect the child's exit status.
POSIX defines no required behavior for an invalid timer ID (EINVAL is
only a recommendation), so the child dying from any signal is treated
as success.
Fixes: d377d1cff1ec ("openposix: timer_*/speculative: Don't pass a stack pointer as timerid")
Suggested-by: Martin Doucha <mdoucha@suse.cz>
Signed-off-by: Avinesh Kumar <avinesh.kumar@suse.com>
---
.../interfaces/timer_delete/speculative/5-1.c | 50 +++++++++++-----
.../timer_getoverrun/speculative/6-1.c | 49 ++++++++++-----
.../timer_gettime/speculative/6-1.c | 52 +++++++++++-----
.../timer_settime/speculative/12-1.c | 60 +++++++++++++------
4 files changed, 145 insertions(+), 66 deletions(-)
diff --git a/testcases/open_posix_testsuite/conformance/interfaces/timer_delete/speculative/5-1.c b/testcases/open_posix_testsuite/conformance/interfaces/timer_delete/speculative/5-1.c
index dce9277b5d6a..d1857efead18 100644
--- a/testcases/open_posix_testsuite/conformance/interfaces/timer_delete/speculative/5-1.c
+++ b/testcases/open_posix_testsuite/conformance/interfaces/timer_delete/speculative/5-1.c
@@ -5,34 +5,52 @@
* of this license, see the COPYING file at the top level of this
* source tree.
- * Test to see if timer_delete() returns -1 and sets errno==EINVAL if
- * timerid is not a valid timer ID or not.
- * Since this is a "may" requirement, either option is a PASS.
+ * Test to see if timer_delete() sets errno==EINVAL for an invalid
+ * timerid. Since this is a "may" requirement, succeeding or crashing
+ * are equally valid outcomes.
*/
#include <time.h>
#include <stdio.h>
#include <errno.h>
+#include <unistd.h>
+#include <sys/wait.h>
#include "posixtest.h"
#define BOGUSTIMERID 99999
int test_main(int argc PTS_ATTRIBUTE_UNUSED, char **argv PTS_ATTRIBUTE_UNUSED)
{
- timer_t tid = (timer_t)BOGUSTIMERID;
-
- if (timer_delete(tid) == -1) {
- if (errno == EINVAL) {
- printf
- ("timer_delete() returned -1 and set errno=EINVAL\n");
- return PTS_PASS;
- } else {
- printf
- ("timer_delete() returned -1, but didn't set errno!=EINVAL\n");
- return PTS_FAIL;
+ pid_t pid;
+ int status;
+
+ pid = fork();
+ if (pid == -1) {
+ perror("fork");
+ return PTS_UNRESOLVED;
+ }
+
+ if (pid == 0) {
+ timer_t tid = (timer_t) BOGUSTIMERID;
+
+ if (timer_delete(tid) == -1) {
+ if (errno == EINVAL)
+ _exit(PTS_PASS);
+ _exit(PTS_FAIL);
}
+ _exit(PTS_PASS);
+ }
+
+ if (waitpid(pid, &status, 0) == -1) {
+ perror("waitpid");
+ return PTS_UNRESOLVED;
+ }
+
+ if (WIFSIGNALED(status) || (WIFEXITED(status) && WEXITSTATUS(status) == 0)) {
+ printf("Test PASSED\n");
+ return PTS_PASS;
}
- printf("timer_delete() did not return -1\n");
- return PTS_PASS;
+ printf("Test FAILED\n");
+ return PTS_FAIL;
}
diff --git a/testcases/open_posix_testsuite/conformance/interfaces/timer_getoverrun/speculative/6-1.c b/testcases/open_posix_testsuite/conformance/interfaces/timer_getoverrun/speculative/6-1.c
index 3a8f1448d4d4..6da435430879 100644
--- a/testcases/open_posix_testsuite/conformance/interfaces/timer_getoverrun/speculative/6-1.c
+++ b/testcases/open_posix_testsuite/conformance/interfaces/timer_getoverrun/speculative/6-1.c
@@ -5,33 +5,52 @@
* of this license, see the COPYING file at the top level of this
* source tree.
*
- * Test to see if timer_getoverrun() sets errno=EINVAL if no timers have been
- * created yet or not. Since this is a "may" assertion, either way is
- * a pass.
+ * Test to see if timer_getoverrun() sets errno==EINVAL for an invalid
+ * timerid. Since this is a "may" assertion, succeeding or crashing
+ * are equally valid outcomes.
*/
#include <time.h>
#include <stdio.h>
#include <errno.h>
+#include <unistd.h>
+#include <sys/wait.h>
#include "posixtest.h"
#define BOGUSTID 9999
int test_main(int argc PTS_ATTRIBUTE_UNUSED, char **argv PTS_ATTRIBUTE_UNUSED)
{
- timer_t tid = (timer_t)BOGUSTID;
-
- if (timer_getoverrun(tid) == -1) {
- if (EINVAL == errno) {
- printf("fcn returned -1 and errno=EINVAL\n");
- return PTS_PASS;
- } else {
- printf("fcn returned -1, but errno!=EINVAL\n");
- printf("Test FAILED\n");
- return PTS_FAIL;
+ pid_t pid;
+ int status;
+
+ pid = fork();
+ if (pid == -1) {
+ perror("fork");
+ return PTS_UNRESOLVED;
+ }
+
+ if (pid == 0) {
+ timer_t tid = (timer_t) BOGUSTID;
+
+ if (timer_getoverrun(tid) == -1) {
+ if (errno == EINVAL)
+ _exit(PTS_PASS);
+ _exit(PTS_FAIL);
}
+ _exit(PTS_PASS);
+ }
+
+ if (waitpid(pid, &status, 0) == -1) {
+ perror("waitpid");
+ return PTS_UNRESOLVED;
+ }
+
+ if (WIFSIGNALED(status) || (WIFEXITED(status) && WEXITSTATUS(status) == 0)) {
+ printf("Test PASSED\n");
+ return PTS_PASS;
}
- printf("fcn did not return -1\n");
- return PTS_PASS;
+ printf("Test FAILED\n");
+ return PTS_FAIL;
}
diff --git a/testcases/open_posix_testsuite/conformance/interfaces/timer_gettime/speculative/6-1.c b/testcases/open_posix_testsuite/conformance/interfaces/timer_gettime/speculative/6-1.c
index 586b0ed3a2b1..ec153e9866da 100644
--- a/testcases/open_posix_testsuite/conformance/interfaces/timer_gettime/speculative/6-1.c
+++ b/testcases/open_posix_testsuite/conformance/interfaces/timer_gettime/speculative/6-1.c
@@ -5,33 +5,53 @@
* of this license, see the COPYING file at the top level of this
* source tree.
*
- * Test to see if timer_gettime() sets errno = EINVAL if no timers have been
- * created yet and it is called with a bogus timer ID. Since this is a "may"
- * assertion, either way is pass.
+ * Test to see if timer_gettime() sets errno==EINVAL for an invalid
+ * timerid. Since this is a "may" assertion, succeeding or crashing
+ * are equally valid outcomes.
*/
#include <time.h>
#include <stdio.h>
#include <errno.h>
+#include <unistd.h>
+#include <sys/wait.h>
#include "posixtest.h"
#define BOGUSTID 9999
int test_main(int argc PTS_ATTRIBUTE_UNUSED, char **argv PTS_ATTRIBUTE_UNUSED)
{
- struct itimerspec its;
- timer_t tid = (timer_t)BOGUSTID;
-
- if (timer_gettime(tid, &its) == -1) {
- if (EINVAL == errno) {
- printf("fcn returned -1 and errno==EINVAL\n");
- return PTS_PASS;
- } else {
- printf("fcn returned -1 but errno!=EINVAL\n");
- printf("Test FAILED\n");
- return PTS_FAIL;
+ pid_t pid;
+ int status;
+
+ pid = fork();
+ if (pid == -1) {
+ perror("fork");
+ return PTS_UNRESOLVED;
+ }
+
+ if (pid == 0) {
+ struct itimerspec its;
+ timer_t tid = (timer_t) BOGUSTID;
+
+ if (timer_gettime(tid, &its) == -1) {
+ if (errno == EINVAL)
+ _exit(PTS_PASS);
+ _exit(PTS_FAIL);
}
+ _exit(PTS_PASS);
}
- printf("fcn did not return -1\n");
- return PTS_PASS;
+
+ if (waitpid(pid, &status, 0) == -1) {
+ perror("waitpid");
+ return PTS_UNRESOLVED;
+ }
+
+ if (WIFSIGNALED(status) || (WIFEXITED(status) && WEXITSTATUS(status) == 0)) {
+ printf("Test PASSED\n");
+ return PTS_PASS;
+ }
+
+ printf("Test FAILED\n");
+ return PTS_FAIL;
}
diff --git a/testcases/open_posix_testsuite/conformance/interfaces/timer_settime/speculative/12-1.c b/testcases/open_posix_testsuite/conformance/interfaces/timer_settime/speculative/12-1.c
index ac7f7bf24c39..f4400ce0dd64 100644
--- a/testcases/open_posix_testsuite/conformance/interfaces/timer_settime/speculative/12-1.c
+++ b/testcases/open_posix_testsuite/conformance/interfaces/timer_settime/speculative/12-1.c
@@ -5,36 +5,58 @@
* of this license, see the COPYING file at the top level of this
* source tree.
*
- * Test to see if timer_settime() sets errno = EINVAL if no timers have been
- * created yet. Since this is a "may" assertion, either way is a pass.
+ * Test to see if timer_settime() sets errno==EINVAL for an invalid
+ * timerid. Since this is a "may" assertion, succeeding or crashing
+ * are equally valid outcomes.
*/
#include <time.h>
#include <stdio.h>
#include <errno.h>
+#include <unistd.h>
+#include <sys/wait.h>
#include "posixtest.h"
#define BOGUSTID 9999
int test_main(int argc PTS_ATTRIBUTE_UNUSED, char **argv PTS_ATTRIBUTE_UNUSED)
{
- struct itimerspec its;
- timer_t tid = (timer_t)BOGUSTID;
- its.it_interval.tv_sec = 0;
- its.it_interval.tv_nsec = 0;
- its.it_value.tv_sec = 0;
- its.it_value.tv_nsec = 0;
-
- if (timer_settime(tid, 0, &its, NULL) == -1) {
- if (EINVAL == errno) {
- printf("fcn returned -1 and errno==EINVAL\n");
- return PTS_PASS;
- } else {
- printf("fcn returned -1, but errno!=EINVAL\n");
- printf("Test FAILED\n");
- return PTS_FAIL;
+ pid_t pid;
+ int status;
+
+ pid = fork();
+ if (pid == -1) {
+ perror("fork");
+ return PTS_UNRESOLVED;
+ }
+
+ if (pid == 0) {
+ struct itimerspec its;
+ timer_t tid = (timer_t) BOGUSTID;
+
+ its.it_interval.tv_sec = 0;
+ its.it_interval.tv_nsec = 0;
+ its.it_value.tv_sec = 0;
+ its.it_value.tv_nsec = 0;
+
+ if (timer_settime(tid, 0, &its, NULL) == -1) {
+ if (errno == EINVAL)
+ _exit(PTS_PASS);
+ _exit(PTS_FAIL);
}
+ _exit(PTS_PASS);
}
- printf("fcn did not return -1\n");
- return PTS_PASS;
+
+ if (waitpid(pid, &status, 0) == -1) {
+ perror("waitpid");
+ return PTS_UNRESOLVED;
+ }
+
+ if (WIFSIGNALED(status) || (WIFEXITED(status) && WEXITSTATUS(status) == 0)) {
+ printf("Test PASSED\n");
+ return PTS_PASS;
+ }
+
+ printf("Test FAILED\n");
+ return PTS_FAIL;
}
--
2.55.0
More information about the ltp
mailing list