1 1.21 uwe /* $NetBSD: t_signal_and_sp.c,v 1.21 2025/04/26 23:49:55 uwe Exp $ */ 2 1.1 pho 3 1.1 pho /* 4 1.1 pho * Copyright (c) 2024 The NetBSD Foundation, Inc. 5 1.1 pho * All rights reserved. 6 1.1 pho * 7 1.1 pho * Redistribution and use in source and binary forms, with or without 8 1.1 pho * modification, are permitted provided that the following conditions 9 1.1 pho * are met: 10 1.1 pho * 1. Redistributions of source code must retain the above copyright 11 1.1 pho * notice, this list of conditions and the following disclaimer. 12 1.1 pho * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 pho * notice, this list of conditions and the following disclaimer in the 14 1.1 pho * documentation and/or other materials provided with the distribution. 15 1.1 pho * 16 1.1 pho * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.1 pho * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 pho * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 pho * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.1 pho * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 pho * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 pho * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 pho * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 pho * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.1 pho * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.1 pho * POSSIBILITY OF SUCH DAMAGE. 27 1.1 pho */ 28 1.1 pho 29 1.20 riastrad #define __EXPOSE_STACK /* <sys/param.h>: expose STACK_ALIGNBYTES */ 30 1.20 riastrad 31 1.2 riastrad #include <sys/cdefs.h> 32 1.21 uwe __RCSID("$NetBSD: t_signal_and_sp.c,v 1.21 2025/04/26 23:49:55 uwe Exp $"); 33 1.2 riastrad 34 1.19 riastrad #include <sys/param.h> 35 1.2 riastrad #include <sys/wait.h> 36 1.2 riastrad 37 1.1 pho #include <atf-c.h> 38 1.2 riastrad #include <limits.h> 39 1.2 riastrad #include <poll.h> 40 1.7 riastrad #include <pthread.h> 41 1.2 riastrad #include <signal.h> 42 1.2 riastrad #include <stdint.h> 43 1.2 riastrad #include <stdio.h> 44 1.10 riastrad #include <stdlib.h> 45 1.2 riastrad #include <string.h> 46 1.2 riastrad #include <time.h> 47 1.7 riastrad #include <ucontext.h> 48 1.2 riastrad #include <unistd.h> 49 1.1 pho 50 1.2 riastrad #include "h_execsp.h" 51 1.2 riastrad #include "h_macros.h" 52 1.2 riastrad 53 1.2 riastrad #ifdef HAVE_STACK_POINTER_H 54 1.1 pho # include "stack_pointer.h" 55 1.2 riastrad #endif 56 1.1 pho 57 1.21 uwe #define PR_59327 "PR kern/59327: user stack pointer is not aligned properly" 58 1.21 uwe 59 1.2 riastrad #ifdef HAVE_SIGNALSPHANDLER 60 1.2 riastrad void signalsphandler(int); /* signalsphandler.S assembly routine */ 61 1.2 riastrad #endif 62 1.2 riastrad 63 1.2 riastrad void *volatile signalsp; 64 1.2 riastrad 65 1.2 riastrad static void 66 1.2 riastrad test_execsp(const struct atf_tc *tc, const char *prog) 67 1.1 pho { 68 1.2 riastrad #ifdef STACK_ALIGNBYTES 69 1.2 riastrad char h_execsp[PATH_MAX]; 70 1.2 riastrad struct execsp execsp; 71 1.2 riastrad int fd[2]; 72 1.2 riastrad pid_t pid; 73 1.2 riastrad struct pollfd pollfd; 74 1.2 riastrad int nfds; 75 1.2 riastrad ssize_t nread; 76 1.2 riastrad int status; 77 1.2 riastrad 78 1.1 pho /* 79 1.2 riastrad * Determine the full path to the helper program. 80 1.1 pho */ 81 1.2 riastrad RL(snprintf(h_execsp, sizeof(h_execsp), "%s/%s", 82 1.2 riastrad atf_tc_get_config_var(tc, "srcdir"), prog)); 83 1.2 riastrad 84 1.2 riastrad /* 85 1.2 riastrad * Create a pipe to read a bundle of stack pointer samples from 86 1.2 riastrad * the child, and fork the child. 87 1.2 riastrad */ 88 1.2 riastrad RL(pipe(fd)); 89 1.2 riastrad RL(pid = vfork()); 90 1.2 riastrad if (pid == 0) { /* child */ 91 1.2 riastrad char *const argv[] = {h_execsp, NULL}; 92 1.2 riastrad 93 1.2 riastrad if (dup2(fd[1], STDOUT_FILENO) == -1) 94 1.2 riastrad _exit(1); 95 1.2 riastrad if (closefrom(STDERR_FILENO + 1) == -1) 96 1.2 riastrad _exit(2); 97 1.2 riastrad if (execve(argv[0], argv, NULL) == -1) 98 1.2 riastrad _exit(3); 99 1.2 riastrad _exit(4); 100 1.2 riastrad } 101 1.2 riastrad 102 1.2 riastrad /* 103 1.2 riastrad * Close the writing end so, if something goes wrong in the 104 1.2 riastrad * child, we don't hang indefinitely waiting for output. 105 1.2 riastrad */ 106 1.2 riastrad RL(close(fd[1])); 107 1.2 riastrad 108 1.2 riastrad /* 109 1.2 riastrad * Wait up to 5sec for the child to return an answer. Any more 110 1.2 riastrad * than that, and we kill it. The child is mostly hand-written 111 1.2 riastrad * assembly routines where lots can go wrong, so don't bother 112 1.2 riastrad * waiting if it gets stuck in a loop. 113 1.2 riastrad */ 114 1.2 riastrad pollfd.fd = fd[0]; 115 1.2 riastrad pollfd.events = POLLIN; 116 1.2 riastrad RL(nfds = poll(&pollfd, 1, 5*1000/*ms*/)); 117 1.2 riastrad if (nfds == 0) { 118 1.2 riastrad fprintf(stderr, "child hung, killing\n"); 119 1.2 riastrad RL(kill(pid, SIGKILL)); 120 1.2 riastrad } 121 1.1 pho 122 1.1 pho /* 123 1.2 riastrad * Read a bundle of stack pointer samples from the child. 124 1.1 pho */ 125 1.2 riastrad RL(nread = read(fd[0], &execsp, sizeof(execsp))); 126 1.2 riastrad ATF_CHECK_MSG((size_t)nread == sizeof(execsp), 127 1.2 riastrad "nread=%zu sizeof(execsp)=%zu", 128 1.2 riastrad (size_t)nread, sizeof(execsp)); 129 1.2 riastrad 130 1.2 riastrad /* 131 1.2 riastrad * Wait for the child to terminate and report failure if it 132 1.2 riastrad * didn't exit cleanly. 133 1.2 riastrad */ 134 1.2 riastrad RL(waitpid(pid, &status, 0)); 135 1.2 riastrad if (WIFSIGNALED(status)) { 136 1.2 riastrad atf_tc_fail_nonfatal("child exited on signal %d (%s)", 137 1.2 riastrad WTERMSIG(status), strsignal(WTERMSIG(status))); 138 1.2 riastrad } else if (!WIFEXITED(status)) { 139 1.2 riastrad atf_tc_fail_nonfatal("child exited status=0x%x", status); 140 1.2 riastrad } else { 141 1.2 riastrad ATF_CHECK_MSG(WEXITSTATUS(status) == 0, 142 1.2 riastrad "child exited with code %d", 143 1.2 riastrad WEXITSTATUS(status)); 144 1.2 riastrad } 145 1.2 riastrad 146 1.2 riastrad /* 147 1.2 riastrad * Now that we have reaped the child, stop here if the stack 148 1.2 riastrad * pointer samples are bogus; otherwise verify they are all 149 1.2 riastrad * aligned. 150 1.2 riastrad */ 151 1.2 riastrad if ((size_t)nread != sizeof(execsp)) 152 1.2 riastrad return; /* failed already */ 153 1.2 riastrad 154 1.2 riastrad printf("start sp @ %p\n", execsp.startsp); 155 1.3 riastrad printf("ctor sp @ %p\n", execsp.ctorsp); 156 1.2 riastrad printf("main sp @ %p\n", execsp.mainsp); 157 1.3 riastrad printf("dtor sp @ %p\n", execsp.dtorsp); 158 1.2 riastrad 159 1.2 riastrad ATF_CHECK_MSG(((uintptr_t)execsp.startsp & STACK_ALIGNBYTES) == 0, 160 1.2 riastrad "elf entry point was called with misaligned sp: %p", 161 1.2 riastrad execsp.startsp); 162 1.2 riastrad 163 1.3 riastrad ATF_CHECK_MSG(((uintptr_t)execsp.ctorsp & STACK_ALIGNBYTES) == 0, 164 1.3 riastrad "elf constructor was called with misaligned sp: %p", 165 1.3 riastrad execsp.ctorsp); 166 1.3 riastrad 167 1.2 riastrad ATF_CHECK_MSG(((uintptr_t)execsp.mainsp & STACK_ALIGNBYTES) == 0, 168 1.2 riastrad "main function was called with misaligned sp: %p", 169 1.2 riastrad execsp.mainsp); 170 1.2 riastrad 171 1.3 riastrad ATF_CHECK_MSG(((uintptr_t)execsp.dtorsp & STACK_ALIGNBYTES) == 0, 172 1.3 riastrad "elf destructor was called with misaligned sp: %p", 173 1.3 riastrad execsp.dtorsp); 174 1.3 riastrad 175 1.2 riastrad /* 176 1.2 riastrad * Leave a reminder on architectures for which we haven't 177 1.2 riastrad * implemented execsp_start.S. 178 1.2 riastrad */ 179 1.3 riastrad if (execsp.startsp == NULL || 180 1.3 riastrad execsp.ctorsp == NULL || 181 1.3 riastrad execsp.mainsp == NULL || 182 1.3 riastrad execsp.dtorsp == NULL) 183 1.2 riastrad atf_tc_skip("Not fully supported on this architecture"); 184 1.2 riastrad #else 185 1.2 riastrad atf_tc_skip("Unknown STACK_ALIGNBYTES on this architecture"); 186 1.2 riastrad #endif 187 1.2 riastrad } 188 1.2 riastrad 189 1.2 riastrad ATF_TC(execsp_dynamic); 190 1.2 riastrad ATF_TC_HEAD(execsp_dynamic, tc) 191 1.2 riastrad { 192 1.2 riastrad atf_tc_set_md_var(tc, "descr", 193 1.2 riastrad "Verify stack pointer is aligned on dynamic program start"); 194 1.2 riastrad } 195 1.2 riastrad ATF_TC_BODY(execsp_dynamic, tc) 196 1.2 riastrad { 197 1.2 riastrad test_execsp(tc, "h_execsp_dynamic"); 198 1.1 pho } 199 1.2 riastrad 200 1.2 riastrad ATF_TC(execsp_static); 201 1.2 riastrad ATF_TC_HEAD(execsp_static, tc) 202 1.2 riastrad { 203 1.2 riastrad atf_tc_set_md_var(tc, "descr", 204 1.2 riastrad "Verify stack pointer is aligned on static program start"); 205 1.2 riastrad } 206 1.2 riastrad ATF_TC_BODY(execsp_static, tc) 207 1.2 riastrad { 208 1.2 riastrad test_execsp(tc, "h_execsp_static"); 209 1.2 riastrad } 210 1.2 riastrad 211 1.7 riastrad #if defined STACK_ALIGNBYTES && defined HAVE_CONTEXTSPFUNC 212 1.7 riastrad void *volatile contextsp; /* set by contextspfunc.S */ 213 1.9 riastrad static ucontext_t return_context; 214 1.7 riastrad static volatile bool test_context_done; 215 1.7 riastrad 216 1.7 riastrad void contextspfunc(void); /* contextspfunc.S assembly routine */ 217 1.7 riastrad 218 1.9 riastrad static void 219 1.9 riastrad contextnoop(void) 220 1.9 riastrad { 221 1.9 riastrad 222 1.9 riastrad fprintf(stderr, "contextnoop\n"); 223 1.9 riastrad /* control will return to contextspfunc via uc_link */ 224 1.9 riastrad } 225 1.9 riastrad 226 1.7 riastrad void contextdone(void); /* called by contextspfunc.S */ 227 1.7 riastrad void 228 1.7 riastrad contextdone(void) 229 1.7 riastrad { 230 1.7 riastrad 231 1.7 riastrad fprintf(stderr, "contextdone\n"); 232 1.7 riastrad ATF_REQUIRE(!test_context_done); 233 1.7 riastrad test_context_done = true; 234 1.7 riastrad RL(setcontext(&return_context)); 235 1.7 riastrad atf_tc_fail("setcontext returned"); 236 1.7 riastrad } 237 1.7 riastrad #endif 238 1.7 riastrad 239 1.7 riastrad ATF_TC(contextsp); 240 1.7 riastrad ATF_TC_HEAD(contextsp, tc) 241 1.7 riastrad { 242 1.7 riastrad atf_tc_set_md_var(tc, "descr", 243 1.7 riastrad "Verify stack pointer is aligned on makecontext entry"); 244 1.7 riastrad } 245 1.7 riastrad ATF_TC_BODY(contextsp, tc) 246 1.7 riastrad { 247 1.7 riastrad #if defined STACK_ALIGNBYTES && defined HAVE_CONTEXTSPFUNC 248 1.9 riastrad ucontext_t uc; 249 1.7 riastrad char *stack; 250 1.7 riastrad unsigned i; 251 1.7 riastrad 252 1.7 riastrad REQUIRE_LIBC(stack = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL); 253 1.9 riastrad fprintf(stderr, "stack @ [%p,%p)\n", stack, 254 1.9 riastrad stack + SIGSTKSZ + STACK_ALIGNBYTES); 255 1.9 riastrad 256 1.9 riastrad for (i = 0; i <= STACK_ALIGNBYTES; i++) { 257 1.9 riastrad contextsp = NULL; 258 1.9 riastrad test_context_done = false; 259 1.9 riastrad 260 1.9 riastrad RL(getcontext(&uc)); 261 1.9 riastrad uc.uc_stack.ss_sp = stack; 262 1.9 riastrad uc.uc_stack.ss_size = SIGSTKSZ + i; 263 1.9 riastrad makecontext(&uc, &contextspfunc, 0); 264 1.9 riastrad 265 1.9 riastrad fprintf(stderr, "[%u] swapcontext\n", i); 266 1.9 riastrad RL(swapcontext(&return_context, &uc)); 267 1.9 riastrad 268 1.9 riastrad ATF_CHECK(contextsp != NULL); 269 1.9 riastrad ATF_CHECK_MSG((uintptr_t)stack <= (uintptr_t)contextsp && 270 1.9 riastrad (uintptr_t)contextsp <= (uintptr_t)stack + SIGSTKSZ + i, 271 1.9 riastrad "contextsp=%p", contextsp); 272 1.9 riastrad ATF_CHECK_MSG(((uintptr_t)contextsp & STACK_ALIGNBYTES) == 0, 273 1.9 riastrad "[%u] makecontext function called with misaligned sp %p", 274 1.9 riastrad i, contextsp); 275 1.9 riastrad } 276 1.9 riastrad 277 1.9 riastrad for (i = 0; i <= STACK_ALIGNBYTES; i++) { 278 1.9 riastrad contextsp = NULL; 279 1.9 riastrad test_context_done = false; 280 1.9 riastrad 281 1.9 riastrad RL(getcontext(&uc)); 282 1.9 riastrad uc.uc_stack.ss_sp = stack + i; 283 1.9 riastrad uc.uc_stack.ss_size = SIGSTKSZ; 284 1.9 riastrad makecontext(&uc, &contextspfunc, 0); 285 1.9 riastrad 286 1.9 riastrad fprintf(stderr, "[%u] swapcontext\n", i); 287 1.9 riastrad RL(swapcontext(&return_context, &uc)); 288 1.9 riastrad 289 1.9 riastrad ATF_CHECK(contextsp != NULL); 290 1.9 riastrad ATF_CHECK_MSG((uintptr_t)stack + i <= (uintptr_t)contextsp && 291 1.9 riastrad (uintptr_t)contextsp <= (uintptr_t)stack + i + SIGSTKSZ, 292 1.9 riastrad "contextsp=%p", contextsp); 293 1.9 riastrad ATF_CHECK_MSG(((uintptr_t)contextsp & STACK_ALIGNBYTES) == 0, 294 1.9 riastrad "[%u] makecontext function called with misaligned sp %p", 295 1.9 riastrad i, contextsp); 296 1.9 riastrad } 297 1.9 riastrad #else 298 1.9 riastrad atf_tc_skip("Not implemented on this platform"); 299 1.9 riastrad #endif 300 1.9 riastrad } 301 1.9 riastrad 302 1.9 riastrad ATF_TC(contextsplink); 303 1.9 riastrad ATF_TC_HEAD(contextsplink, tc) 304 1.9 riastrad { 305 1.9 riastrad atf_tc_set_md_var(tc, "descr", 306 1.9 riastrad "Verify stack pointer is aligned on makecontext link entry"); 307 1.9 riastrad } 308 1.9 riastrad ATF_TC_BODY(contextsplink, tc) 309 1.9 riastrad { 310 1.9 riastrad #if defined STACK_ALIGNBYTES && defined HAVE_CONTEXTSPFUNC 311 1.9 riastrad ucontext_t uc1, uc2; 312 1.9 riastrad char *stack1, *stack2; 313 1.9 riastrad unsigned i; 314 1.9 riastrad 315 1.9 riastrad REQUIRE_LIBC(stack1 = malloc(SIGSTKSZ), NULL); 316 1.9 riastrad fprintf(stderr, "stack1 @ [%p,%p)\n", stack1, stack1 + SIGSTKSZ); 317 1.9 riastrad REQUIRE_LIBC(stack2 = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL); 318 1.9 riastrad fprintf(stderr, "stack2 @ [%p,%p)\n", 319 1.9 riastrad stack2, stack2 + SIGSTKSZ + STACK_ALIGNBYTES); 320 1.9 riastrad 321 1.7 riastrad for (i = 0; i <= STACK_ALIGNBYTES; i++) { 322 1.7 riastrad contextsp = NULL; 323 1.7 riastrad test_context_done = false; 324 1.9 riastrad 325 1.9 riastrad RL(getcontext(&uc1)); 326 1.9 riastrad uc1.uc_stack.ss_sp = stack1; 327 1.9 riastrad uc1.uc_stack.ss_size = SIGSTKSZ; 328 1.9 riastrad uc1.uc_link = &uc2; 329 1.9 riastrad makecontext(&uc1, &contextnoop, 0); 330 1.9 riastrad 331 1.9 riastrad RL(getcontext(&uc2)); 332 1.9 riastrad uc2.uc_stack.ss_sp = stack2; 333 1.9 riastrad uc2.uc_stack.ss_size = SIGSTKSZ + i; 334 1.9 riastrad makecontext(&uc2, &contextspfunc, 0); 335 1.9 riastrad 336 1.7 riastrad fprintf(stderr, "[%u] swapcontext\n", i); 337 1.9 riastrad RL(swapcontext(&return_context, &uc1)); 338 1.9 riastrad 339 1.7 riastrad ATF_CHECK(contextsp != NULL); 340 1.9 riastrad ATF_CHECK_MSG((uintptr_t)stack2 <= (uintptr_t)contextsp && 341 1.9 riastrad (uintptr_t)contextsp <= (uintptr_t)stack2 + SIGSTKSZ + i, 342 1.9 riastrad "contextsp=%p", contextsp); 343 1.7 riastrad ATF_CHECK_MSG(((uintptr_t)contextsp & STACK_ALIGNBYTES) == 0, 344 1.7 riastrad "[%u] makecontext function called with misaligned sp %p", 345 1.7 riastrad i, contextsp); 346 1.7 riastrad } 347 1.7 riastrad 348 1.7 riastrad for (i = 0; i <= STACK_ALIGNBYTES; i++) { 349 1.7 riastrad contextsp = NULL; 350 1.7 riastrad test_context_done = false; 351 1.9 riastrad 352 1.9 riastrad RL(getcontext(&uc1)); 353 1.9 riastrad uc1.uc_stack.ss_sp = stack1; 354 1.9 riastrad uc1.uc_stack.ss_size = SIGSTKSZ; 355 1.9 riastrad uc1.uc_link = &uc2; 356 1.9 riastrad makecontext(&uc1, &contextnoop, 0); 357 1.9 riastrad 358 1.9 riastrad RL(getcontext(&uc2)); 359 1.9 riastrad uc2.uc_stack.ss_sp = stack2 + i; 360 1.9 riastrad uc2.uc_stack.ss_size = SIGSTKSZ; 361 1.9 riastrad makecontext(&uc2, &contextspfunc, 0); 362 1.9 riastrad 363 1.7 riastrad fprintf(stderr, "[%u] swapcontext\n", i); 364 1.9 riastrad RL(swapcontext(&return_context, &uc1)); 365 1.9 riastrad 366 1.7 riastrad ATF_CHECK(contextsp != NULL); 367 1.9 riastrad ATF_CHECK_MSG((uintptr_t)stack2 + i <= (uintptr_t)contextsp && 368 1.9 riastrad (uintptr_t)contextsp <= (uintptr_t)stack2 + SIGSTKSZ + i, 369 1.9 riastrad "contextsp=%p", contextsp); 370 1.7 riastrad ATF_CHECK_MSG(((uintptr_t)contextsp & STACK_ALIGNBYTES) == 0, 371 1.7 riastrad "[%u] makecontext function called with misaligned sp %p", 372 1.7 riastrad i, contextsp); 373 1.7 riastrad } 374 1.7 riastrad #else 375 1.7 riastrad atf_tc_skip("Not implemented on this platform"); 376 1.7 riastrad #endif 377 1.7 riastrad } 378 1.7 riastrad 379 1.2 riastrad ATF_TC(signalsp); 380 1.2 riastrad ATF_TC_HEAD(signalsp, tc) 381 1.2 riastrad { 382 1.2 riastrad atf_tc_set_md_var(tc, "descr", 383 1.2 riastrad "Verify stack pointer is aligned on entry to signal handler"); 384 1.2 riastrad } 385 1.2 riastrad ATF_TC_BODY(signalsp, tc) 386 1.2 riastrad { 387 1.2 riastrad #if defined STACK_ALIGNBYTES && defined HAVE_SIGNALSPHANDLER 388 1.2 riastrad struct sigaction sa; 389 1.2 riastrad 390 1.2 riastrad memset(&sa, 0, sizeof(sa)); 391 1.2 riastrad sa.sa_handler = &signalsphandler; 392 1.2 riastrad RL(sigaction(SIGUSR1, &sa, NULL)); 393 1.2 riastrad RL(raise(SIGUSR1)); 394 1.2 riastrad 395 1.2 riastrad ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0, 396 1.2 riastrad "signal handler was called with a misaligned sp: %p", 397 1.2 riastrad signalsp); 398 1.2 riastrad #else 399 1.2 riastrad atf_tc_skip("Not implemented on this platform"); 400 1.2 riastrad #endif 401 1.2 riastrad } 402 1.2 riastrad 403 1.2 riastrad ATF_TC(signalsp_sigaltstack); 404 1.2 riastrad ATF_TC_HEAD(signalsp_sigaltstack, tc) 405 1.2 riastrad { 406 1.2 riastrad atf_tc_set_md_var(tc, "descr", 407 1.2 riastrad "Verify stack pointer is aligned on entry to signal handler" 408 1.2 riastrad " with maximally misaligned sigaltstack"); 409 1.2 riastrad } 410 1.2 riastrad ATF_TC_BODY(signalsp_sigaltstack, tc) 411 1.2 riastrad { 412 1.2 riastrad #if defined STACK_ALIGNBYTES && HAVE_SIGNALSPHANDLER 413 1.21 uwe #if defined(__sh__) 414 1.21 uwe atf_tc_expect_fail(PR_59327); 415 1.21 uwe #endif 416 1.2 riastrad char *stack; 417 1.2 riastrad struct sigaction sa; 418 1.2 riastrad struct sigaltstack ss; 419 1.2 riastrad unsigned i; 420 1.2 riastrad 421 1.2 riastrad memset(&sa, 0, sizeof(sa)); 422 1.2 riastrad sa.sa_handler = &signalsphandler; 423 1.2 riastrad sa.sa_flags = SA_ONSTACK; 424 1.2 riastrad RL(sigaction(SIGUSR1, &sa, NULL)); 425 1.2 riastrad 426 1.2 riastrad /* 427 1.2 riastrad * Allocate a signal stack with enough slop to try all possible 428 1.2 riastrad * misalignments of the stack pointer. Print it to stderr so 429 1.2 riastrad * it always appears in atf output before shenanigans happen. 430 1.2 riastrad */ 431 1.2 riastrad REQUIRE_LIBC(stack = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL); 432 1.7 riastrad fprintf(stderr, "stack @ [%p, %p)\n", 433 1.2 riastrad stack, stack + SIGSTKSZ + STACK_ALIGNBYTES); 434 1.2 riastrad 435 1.2 riastrad /* 436 1.2 riastrad * Try with all alignments of high addresses. 437 1.2 riastrad */ 438 1.2 riastrad for (i = 0; i <= STACK_ALIGNBYTES; i++) { 439 1.2 riastrad ss.ss_sp = stack; 440 1.2 riastrad ss.ss_size = SIGSTKSZ + i; 441 1.2 riastrad ss.ss_flags = 0; 442 1.2 riastrad RL(sigaltstack(&ss, NULL)); 443 1.2 riastrad 444 1.2 riastrad signalsp = NULL; 445 1.2 riastrad RL(raise(SIGUSR1)); 446 1.2 riastrad ATF_CHECK(signalsp != NULL); 447 1.9 riastrad ATF_CHECK_MSG((uintptr_t)stack <= (uintptr_t)signalsp && 448 1.9 riastrad (uintptr_t)signalsp <= (uintptr_t)stack + SIGSTKSZ + i, 449 1.9 riastrad "signalsp=%p", signalsp); 450 1.2 riastrad ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0, 451 1.2 riastrad "[%u] signal handler was called with a misaligned sp: %p", 452 1.2 riastrad i, signalsp); 453 1.2 riastrad } 454 1.2 riastrad 455 1.2 riastrad /* 456 1.2 riastrad * Try with all alignments of low addresses. 457 1.2 riastrad */ 458 1.2 riastrad for (i = 0; i <= STACK_ALIGNBYTES; i++) { 459 1.2 riastrad ss.ss_sp = stack + i; 460 1.2 riastrad ss.ss_size = SIGSTKSZ; 461 1.2 riastrad ss.ss_flags = 0; 462 1.2 riastrad RL(sigaltstack(&ss, NULL)); 463 1.2 riastrad 464 1.2 riastrad signalsp = NULL; 465 1.2 riastrad RL(raise(SIGUSR1)); 466 1.2 riastrad ATF_CHECK(signalsp != NULL); 467 1.9 riastrad ATF_CHECK_MSG((uintptr_t)stack + i <= (uintptr_t)signalsp && 468 1.9 riastrad (uintptr_t)signalsp <= (uintptr_t)stack + i + SIGSTKSZ, 469 1.9 riastrad "signalsp=%p", signalsp); 470 1.2 riastrad ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0, 471 1.2 riastrad "[%u] signal handler was called with a misaligned sp: %p", 472 1.2 riastrad i, signalsp); 473 1.2 riastrad } 474 1.2 riastrad #else 475 1.2 riastrad atf_tc_skip("Not implemented on this platform"); 476 1.1 pho #endif 477 1.2 riastrad } 478 1.1 pho 479 1.7 riastrad #if defined STACK_ALIGNBYTES && defined HAVE_THREADSPFUNC 480 1.7 riastrad void *threadspfunc(void *); /* threadspfunc.S assembly routine */ 481 1.7 riastrad #endif 482 1.7 riastrad 483 1.7 riastrad ATF_TC(threadsp); 484 1.7 riastrad ATF_TC_HEAD(threadsp, tc) 485 1.7 riastrad { 486 1.7 riastrad atf_tc_set_md_var(tc, "descr", 487 1.7 riastrad "Verify stack pointer is aligned on thread start"); 488 1.7 riastrad } 489 1.7 riastrad ATF_TC_BODY(threadsp, tc) 490 1.7 riastrad { 491 1.7 riastrad #if defined STACK_ALIGNBYTES && defined HAVE_THREADSPFUNC 492 1.14 riastrad pthread_t t; 493 1.14 riastrad void *sp; 494 1.7 riastrad char *stack; 495 1.7 riastrad unsigned i; 496 1.7 riastrad 497 1.7 riastrad REQUIRE_LIBC(stack = malloc(SIGSTKSZ + STACK_ALIGNBYTES), NULL); 498 1.9 riastrad fprintf(stderr, "stack @ [%p,%p)\n", stack, 499 1.9 riastrad stack + SIGSTKSZ + STACK_ALIGNBYTES); 500 1.9 riastrad 501 1.14 riastrad RZ(pthread_create(&t, NULL, &threadspfunc, NULL)); 502 1.14 riastrad 503 1.14 riastrad alarm(1); 504 1.14 riastrad RZ(pthread_join(t, &sp)); 505 1.14 riastrad alarm(0); 506 1.14 riastrad 507 1.14 riastrad ATF_CHECK(sp != NULL); 508 1.14 riastrad ATF_CHECK_MSG(((uintptr_t)sp & STACK_ALIGNBYTES) == 0, 509 1.14 riastrad "thread called with misaligned sp: %p", sp); 510 1.14 riastrad 511 1.7 riastrad for (i = 0; i <= STACK_ALIGNBYTES; i++) { 512 1.7 riastrad pthread_attr_t attr; 513 1.7 riastrad 514 1.7 riastrad RZ(pthread_attr_init(&attr)); 515 1.7 riastrad RZ(pthread_attr_setstack(&attr, stack, SIGSTKSZ + i)); 516 1.7 riastrad RZ(pthread_create(&t, &attr, &threadspfunc, NULL)); 517 1.7 riastrad RZ(pthread_attr_destroy(&attr)); 518 1.7 riastrad 519 1.7 riastrad alarm(1); 520 1.7 riastrad RZ(pthread_join(t, &sp)); 521 1.7 riastrad alarm(0); 522 1.7 riastrad 523 1.7 riastrad ATF_CHECK(sp != NULL); 524 1.9 riastrad ATF_CHECK_MSG((uintptr_t)stack <= (uintptr_t)sp && 525 1.9 riastrad (uintptr_t)sp <= (uintptr_t)stack + SIGSTKSZ + i, 526 1.9 riastrad "sp=%p", sp); 527 1.10 riastrad ATF_CHECK_MSG(((uintptr_t)sp & STACK_ALIGNBYTES) == 0, 528 1.10 riastrad "[%u] thread called with misaligned sp: %p", i, sp); 529 1.7 riastrad } 530 1.7 riastrad 531 1.7 riastrad for (i = 0; i <= STACK_ALIGNBYTES; i++) { 532 1.7 riastrad pthread_attr_t attr; 533 1.7 riastrad 534 1.7 riastrad RZ(pthread_attr_init(&attr)); 535 1.7 riastrad RZ(pthread_attr_setstack(&attr, stack + i, SIGSTKSZ)); 536 1.7 riastrad RZ(pthread_create(&t, &attr, &threadspfunc, NULL)); 537 1.7 riastrad RZ(pthread_attr_destroy(&attr)); 538 1.7 riastrad 539 1.7 riastrad alarm(1); 540 1.7 riastrad RZ(pthread_join(t, &sp)); 541 1.7 riastrad alarm(0); 542 1.7 riastrad 543 1.7 riastrad ATF_CHECK(sp != NULL); 544 1.9 riastrad ATF_CHECK_MSG((uintptr_t)stack + i <= (uintptr_t)sp && 545 1.9 riastrad (uintptr_t)sp <= (uintptr_t)stack + i + SIGSTKSZ, 546 1.9 riastrad "sp=%p", sp); 547 1.10 riastrad ATF_CHECK_MSG(((uintptr_t)sp & STACK_ALIGNBYTES) == 0, 548 1.10 riastrad "[%u] thread called with misaligned sp: %p", i, sp); 549 1.7 riastrad } 550 1.7 riastrad #else 551 1.7 riastrad atf_tc_skip("Not implemented on this platform"); 552 1.7 riastrad #endif 553 1.7 riastrad } 554 1.7 riastrad 555 1.1 pho ATF_TC(misaligned_sp_and_signal); 556 1.1 pho ATF_TC_HEAD(misaligned_sp_and_signal, tc) 557 1.1 pho { 558 1.1 pho atf_tc_set_md_var(tc, "descr", "process can return from a signal" 559 1.1 pho " handler even if the stack pointer is misaligned when a signal" 560 1.1 pho " arrives"); 561 1.1 pho } 562 1.1 pho ATF_TC_BODY(misaligned_sp_and_signal, tc) 563 1.1 pho { 564 1.2 riastrad #if defined STACK_ALIGNBYTES && defined HAVE_STACK_POINTER_H 565 1.21 uwe #if defined(__sh__) 566 1.21 uwe atf_tc_expect_fail(PR_59327); 567 1.21 uwe #endif 568 1.21 uwe 569 1.1 pho /* 570 1.1 pho * Set up a handler for SIGALRM. 571 1.1 pho */ 572 1.1 pho struct sigaction sa; 573 1.1 pho memset(&sa, 0, sizeof(sa)); 574 1.2 riastrad sa.sa_handler = &signalsphandler; 575 1.2 riastrad RL(sigaction(SIGALRM, &sa, NULL)); 576 1.1 pho 577 1.1 pho /* 578 1.1 pho * Set up an interval timer so that we receive SIGALRM after 50 ms. 579 1.1 pho */ 580 1.1 pho struct itimerval itv; 581 1.1 pho memset(&itv, 0, sizeof(itv)); 582 1.1 pho itv.it_value.tv_usec = 1000 * 50; 583 1.2 riastrad RL(setitimer(ITIMER_MONOTONIC, &itv, NULL)); 584 1.1 pho 585 1.1 pho /* 586 1.1 pho * Now misalign the SP. Wait for the signal to arrive and see what 587 1.1 pho * happens. This should be fine as long as we don't use it to 588 1.1 pho * access memory. 589 1.1 pho */ 590 1.1 pho MISALIGN_SP; 591 1.2 riastrad while (signalsp == NULL) { 592 1.1 pho /* 593 1.1 pho * Make sure the compiler does not optimize this busy loop 594 1.1 pho * away. 595 1.1 pho */ 596 1.2 riastrad __asm__("" ::: "memory"); 597 1.1 pho } 598 1.1 pho /* 599 1.1 pho * We could successfully return from a signal handler. Now we 600 1.1 pho * should fix the SP before calling any functions. 601 1.1 pho */ 602 1.1 pho FIX_SP; 603 1.1 pho 604 1.1 pho /* 605 1.1 pho * But was the stack pointer aligned when we were on the signal 606 1.1 pho * handler? 607 1.1 pho */ 608 1.2 riastrad ATF_CHECK_MSG(((uintptr_t)signalsp & STACK_ALIGNBYTES) == 0, 609 1.1 pho "signal handler was called with a misaligned sp: %p", 610 1.2 riastrad signalsp); 611 1.1 pho #else 612 1.1 pho atf_tc_skip("Not implemented for this platform"); 613 1.1 pho #endif 614 1.1 pho } 615 1.1 pho 616 1.1 pho ATF_TP_ADD_TCS(tp) 617 1.1 pho { 618 1.2 riastrad 619 1.7 riastrad ATF_TP_ADD_TC(tp, contextsp); 620 1.9 riastrad ATF_TP_ADD_TC(tp, contextsplink); 621 1.2 riastrad ATF_TP_ADD_TC(tp, execsp_dynamic); 622 1.2 riastrad ATF_TP_ADD_TC(tp, execsp_static); 623 1.1 pho ATF_TP_ADD_TC(tp, misaligned_sp_and_signal); 624 1.2 riastrad ATF_TP_ADD_TC(tp, signalsp); 625 1.2 riastrad ATF_TP_ADD_TC(tp, signalsp_sigaltstack); 626 1.7 riastrad ATF_TP_ADD_TC(tp, threadsp); 627 1.1 pho return atf_no_error(); 628 1.1 pho } 629