1 1.1 riastrad /* $NetBSD: getstack.c,v 1.1 2026/08/28 06:35:26 riastradh Exp $ */ 2 1.1 riastrad 3 1.1 riastrad /*- 4 1.1 riastrad * Copyright (c) 2026 The NetBSD Foundation, Inc. 5 1.1 riastrad * All rights reserved. 6 1.1 riastrad * 7 1.1 riastrad * Redistribution and use in source and binary forms, with or without 8 1.1 riastrad * modification, are permitted provided that the following conditions 9 1.1 riastrad * are met: 10 1.1 riastrad * 1. Redistributions of source code must retain the above copyright 11 1.1 riastrad * notice, this list of conditions and the following disclaimer. 12 1.1 riastrad * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 riastrad * notice, this list of conditions and the following disclaimer in the 14 1.1 riastrad * documentation and/or other materials provided with the distribution. 15 1.1 riastrad * 16 1.1 riastrad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.1 riastrad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 riastrad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 riastrad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.1 riastrad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 riastrad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 riastrad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 riastrad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 riastrad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.1 riastrad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.1 riastrad * POSSIBILITY OF SUCH DAMAGE. 27 1.1 riastrad */ 28 1.1 riastrad 29 1.1 riastrad #include <sys/cdefs.h> 30 1.1 riastrad __RCSID("$NetBSD: getstack.c,v 1.1 2026/08/28 06:35:26 riastradh Exp $"); 31 1.1 riastrad 32 1.1 riastrad #include "getstack.h" 33 1.1 riastrad 34 1.1 riastrad #include <sys/exec.h> 35 1.1 riastrad #include <sys/exec_elf.h> 36 1.1 riastrad #include <sys/resource.h> 37 1.1 riastrad #include <sys/sysctl.h> 38 1.1 riastrad #include <sys/types.h> 39 1.1 riastrad 40 1.1 riastrad #include <dlfcn.h> 41 1.1 riastrad #include <err.h> 42 1.1 riastrad #include <pthread.h> 43 1.1 riastrad #include <signal.h> 44 1.1 riastrad #include <ucontext.h> 45 1.1 riastrad #include <unistd.h> 46 1.1 riastrad 47 1.1 riastrad extern struct ps_strings *__ps_strings; /* XXX */ 48 1.1 riastrad 49 1.1 riastrad void * 50 1.1 riastrad getstack_elf_auxv(void) 51 1.1 riastrad { 52 1.1 riastrad const AuxInfo *aux; 53 1.1 riastrad 54 1.1 riastrad for (aux = _dlauxinfo(); aux->a_type != AT_NULL; aux++) { 55 1.1 riastrad if (aux->a_type == AT_STACKBASE) 56 1.1 riastrad return (void *)aux->a_v; 57 1.1 riastrad } 58 1.1 riastrad warnx("missing AT_STACKBASE in ELF auxv"); 59 1.1 riastrad return NULL; 60 1.1 riastrad } 61 1.1 riastrad 62 1.1 riastrad void * 63 1.1 riastrad getstack_getcontext(size_t *usedsizep) 64 1.1 riastrad { 65 1.1 riastrad ucontext_t uc; 66 1.1 riastrad 67 1.1 riastrad if (getcontext(&uc) == -1) { 68 1.1 riastrad warn("getcontext"); 69 1.1 riastrad *usedsizep = (size_t)-1; 70 1.1 riastrad return NULL; 71 1.1 riastrad } 72 1.1 riastrad *usedsizep = uc.uc_stack.ss_size; 73 1.1 riastrad return uc.uc_stack.ss_sp; 74 1.1 riastrad } 75 1.1 riastrad 76 1.1 riastrad void * 77 1.1 riastrad getstack_psstrings(void) 78 1.1 riastrad { 79 1.1 riastrad 80 1.1 riastrad if (__ps_strings == NULL) { 81 1.1 riastrad warnx("missing __ps_strings"); 82 1.1 riastrad return NULL; 83 1.1 riastrad } 84 1.1 riastrad 85 1.1 riastrad #ifdef __MACHINE_STACK_GROWS_UP 86 1.1 riastrad return __ps_strings; 87 1.1 riastrad #else 88 1.1 riastrad return (char *)__ps_strings + sizeof(*__ps_strings); 89 1.1 riastrad #endif 90 1.1 riastrad } 91 1.1 riastrad 92 1.1 riastrad void * 93 1.1 riastrad getstack_pthreadattr(size_t *minsizep) 94 1.1 riastrad { 95 1.1 riastrad pthread_attr_t attr_storage, *attr = NULL; 96 1.1 riastrad void *addr = NULL; 97 1.1 riastrad int error; 98 1.1 riastrad 99 1.1 riastrad error = pthread_getattr_np(pthread_self(), &attr_storage); 100 1.1 riastrad if (error) { 101 1.1 riastrad warnc(error, "pthread_getattr_np"); 102 1.1 riastrad addr = NULL; 103 1.1 riastrad *minsizep = (size_t)-1; 104 1.1 riastrad goto out; 105 1.1 riastrad } 106 1.1 riastrad attr = &attr_storage; 107 1.1 riastrad 108 1.1 riastrad error = pthread_attr_getstack(attr, &addr, minsizep); 109 1.1 riastrad if (error) { 110 1.1 riastrad warnc(error, "pthread_attr_getstack"); 111 1.1 riastrad addr = NULL; 112 1.1 riastrad *minsizep = (size_t)-1; 113 1.1 riastrad goto out; 114 1.1 riastrad } 115 1.1 riastrad 116 1.1 riastrad #ifndef __MACHINE_STACK_GROWS_UP 117 1.1 riastrad addr = (char *)addr + *minsizep; 118 1.1 riastrad #endif 119 1.1 riastrad 120 1.1 riastrad out: error = pthread_attr_destroy(attr); 121 1.1 riastrad if (error) 122 1.1 riastrad warnc(error, "pthread_attr_destroy"); 123 1.1 riastrad return addr; 124 1.1 riastrad } 125 1.1 riastrad 126 1.1 riastrad void 127 1.1 riastrad getstack_rlimit(size_t *minsizep, size_t *maxsizep) 128 1.1 riastrad { 129 1.1 riastrad struct rlimit rlim; 130 1.1 riastrad 131 1.1 riastrad if (getrlimit(RLIMIT_STACK, &rlim) == -1) { 132 1.1 riastrad warn("getrlimit(RLIMIT_STACK)"); 133 1.1 riastrad *minsizep = (size_t)-1; 134 1.1 riastrad *maxsizep = (size_t)-1; 135 1.1 riastrad return; 136 1.1 riastrad } 137 1.1 riastrad *minsizep = rlim.rlim_cur; 138 1.1 riastrad *maxsizep = rlim.rlim_max; 139 1.1 riastrad } 140 1.1 riastrad 141 1.1 riastrad void * 142 1.1 riastrad getstack_sigaltstack(size_t *minsizep) 143 1.1 riastrad { 144 1.1 riastrad stack_t ss; 145 1.1 riastrad 146 1.1 riastrad if (sigaltstack(NULL, &ss) == -1) { 147 1.1 riastrad warn("sigaltstack"); 148 1.1 riastrad *minsizep = (size_t)-1; 149 1.1 riastrad return NULL; 150 1.1 riastrad } 151 1.1 riastrad *minsizep = ss.ss_size; 152 1.1 riastrad return ss.ss_sp; 153 1.1 riastrad } 154 1.1 riastrad 155 1.1 riastrad int 156 1.1 riastrad checkgetstack(void) 157 1.1 riastrad { 158 1.1 riastrad void *addr_elf_auxv; 159 1.1 riastrad void *addr_getcontext; 160 1.1 riastrad void *addr_psstrings; 161 1.1 riastrad void *addr_pthreadattr; 162 1.1 riastrad void *addr_sigaltstack; 163 1.1 riastrad size_t usedsize_getcontext; 164 1.1 riastrad size_t minsize_pthreadattr; 165 1.1 riastrad size_t minsize_rlimit; 166 1.1 riastrad size_t maxsize_rlimit; 167 1.1 riastrad size_t minsize_sigaltstack; 168 1.1 riastrad 169 1.1 riastrad addr_elf_auxv = getstack_elf_auxv(); 170 1.1 riastrad addr_getcontext = getstack_getcontext(&usedsize_getcontext); 171 1.1 riastrad addr_psstrings = getstack_psstrings(); 172 1.1 riastrad addr_pthreadattr = getstack_pthreadattr(&minsize_pthreadattr); 173 1.1 riastrad getstack_rlimit(&minsize_rlimit, &maxsize_rlimit); 174 1.1 riastrad addr_sigaltstack = getstack_sigaltstack(&minsize_sigaltstack); 175 1.1 riastrad 176 1.1 riastrad warnx("%16s: addr=%p", "ELF AT_STACKBASE", addr_elf_auxv); 177 1.1 riastrad warnx("%16s: addr=%-16p used=%zx", "getcontext", 178 1.1 riastrad addr_getcontext, usedsize_getcontext); 179 1.1 riastrad warnx("%16s: addr=%p", "__ps_strings", addr_psstrings); 180 1.1 riastrad warnx("%16s: addr=%-16p size=%zx", "pthread attr", 181 1.1 riastrad addr_pthreadattr, minsize_pthreadattr); 182 1.1 riastrad warnx("%16s: %-16s size=%zx min, %zx max", "RLIMIT_STACK", 183 1.1 riastrad "", minsize_rlimit, maxsize_rlimit); 184 1.1 riastrad warnx("%16s: addr=%-16p size=%zx", "sigaltstack", 185 1.1 riastrad addr_sigaltstack, minsize_sigaltstack); 186 1.1 riastrad 187 1.1 riastrad if (addr_elf_auxv == addr_getcontext && 188 1.1 riastrad addr_elf_auxv == addr_psstrings && 189 1.1 riastrad addr_elf_auxv == addr_pthreadattr && 190 1.1 riastrad (addr_sigaltstack == NULL || addr_elf_auxv == addr_sigaltstack) && 191 1.1 riastrad usedsize_getcontext <= minsize_rlimit && 192 1.1 riastrad minsize_pthreadattr == minsize_rlimit && 193 1.1 riastrad (addr_sigaltstack == NULL || 194 1.1 riastrad minsize_pthreadattr == minsize_sigaltstack) && 195 1.1 riastrad minsize_rlimit <= maxsize_rlimit) { 196 1.1 riastrad warnx("Stack OK"); 197 1.1 riastrad return 0; 198 1.1 riastrad } 199 1.1 riastrad 200 1.1 riastrad warnx("Stack disagreement!"); 201 1.1 riastrad return -1; 202 1.1 riastrad } 203 1.1 riastrad 204 1.1 riastrad int 205 1.1 riastrad checkgetstack_singlethreaded(void) 206 1.1 riastrad { 207 1.1 riastrad void *addr_elf_auxv; 208 1.1 riastrad void *addr_getcontext; 209 1.1 riastrad void *addr_psstrings; 210 1.1 riastrad void *addr_sigaltstack; 211 1.1 riastrad size_t usedsize_getcontext; 212 1.1 riastrad size_t minsize_rlimit; 213 1.1 riastrad size_t maxsize_rlimit; 214 1.1 riastrad size_t minsize_sigaltstack; 215 1.1 riastrad 216 1.1 riastrad addr_elf_auxv = getstack_elf_auxv(); 217 1.1 riastrad addr_getcontext = getstack_getcontext(&usedsize_getcontext); 218 1.1 riastrad addr_psstrings = getstack_psstrings(); 219 1.1 riastrad getstack_rlimit(&minsize_rlimit, &maxsize_rlimit); 220 1.1 riastrad addr_sigaltstack = getstack_sigaltstack(&minsize_sigaltstack); 221 1.1 riastrad 222 1.1 riastrad warnx("%16s: addr=%p", "ELF AT_STACKBASE", addr_elf_auxv); 223 1.1 riastrad warnx("%16s: addr=%-16p used=%zx", "getcontext", 224 1.1 riastrad addr_getcontext, usedsize_getcontext); 225 1.1 riastrad warnx("%16s: addr=%p", "__ps_strings", addr_psstrings); 226 1.1 riastrad warnx("%16s: %-16s size=%zx min, %zx max", "RLIMIT_STACK", 227 1.1 riastrad "", minsize_rlimit, maxsize_rlimit); 228 1.1 riastrad warnx("%16s: addr=%-16p size=%zx", "sigaltstack", 229 1.1 riastrad addr_sigaltstack, minsize_sigaltstack); 230 1.1 riastrad 231 1.1 riastrad if (addr_elf_auxv == addr_getcontext && 232 1.1 riastrad addr_elf_auxv == addr_psstrings && 233 1.1 riastrad (addr_sigaltstack == NULL || addr_elf_auxv == addr_sigaltstack) && 234 1.1 riastrad usedsize_getcontext <= minsize_rlimit && 235 1.1 riastrad (addr_sigaltstack == NULL || 236 1.1 riastrad minsize_rlimit == minsize_sigaltstack) && 237 1.1 riastrad minsize_rlimit <= maxsize_rlimit) { 238 1.1 riastrad warnx("Stack OK"); 239 1.1 riastrad return 0; 240 1.1 riastrad } 241 1.1 riastrad 242 1.1 riastrad warnx("Stack disagreement!"); 243 1.1 riastrad return -1; 244 1.1 riastrad } 245