kern_pax.c revision 1.32
1/* $NetBSD: kern_pax.c,v 1.32 2015/09/26 16:12:24 maxv Exp $ */ 2 3/* 4 * Copyright (c) 2015 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Maxime Villard. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32/* 33 * Copyright (c) 2006 Elad Efrat <elad@NetBSD.org> 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. The name of the author may not be used to endorse or promote products 45 * derived from this software without specific prior written permission. 46 * 47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 48 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 49 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 50 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 51 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 52 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 53 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 54 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 55 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 56 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 57 */ 58 59#include <sys/cdefs.h> 60__KERNEL_RCSID(0, "$NetBSD: kern_pax.c,v 1.32 2015/09/26 16:12:24 maxv Exp $"); 61 62#include "opt_pax.h" 63 64#include <sys/param.h> 65#include <sys/proc.h> 66#include <sys/exec_elf.h> 67#include <sys/pax.h> 68#include <sys/sysctl.h> 69#include <sys/kmem.h> 70#include <sys/fileassoc.h> 71#include <sys/syslog.h> 72#include <sys/vnode.h> 73#include <sys/queue.h> 74#include <sys/kauth.h> 75#include <sys/cprng.h> 76 77#ifdef PAX_ASLR_DEBUG 78#define PAX_DPRINTF(_fmt, args...) uprintf("%s: " _fmt "\n", __func__, ##args) 79#else 80#define PAX_DPRINTF(_fmt, args...) do {} while (/*CONSTCOND*/0) 81#endif 82 83#ifdef PAX_ASLR 84#include <sys/mman.h> 85#include <sys/exec.h> 86 87int pax_aslr_enabled = 1; 88int pax_aslr_global = PAX_ASLR; 89 90#ifndef PAX_ASLR_DELTA_MMAP_LSB 91#define PAX_ASLR_DELTA_MMAP_LSB PGSHIFT 92#endif 93#ifndef PAX_ASLR_DELTA_MMAP_LEN 94#define PAX_ASLR_DELTA_MMAP_LEN ((sizeof(void *) * NBBY) / 2) 95#endif 96#ifndef PAX_ASLR_DELTA_STACK_LSB 97#define PAX_ASLR_DELTA_STACK_LSB PGSHIFT 98#endif 99#ifndef PAX_ASLR_DELTA_STACK_LEN 100#define PAX_ASLR_DELTA_STACK_LEN 12 101#endif 102 103static bool pax_aslr_elf_flags_active(uint32_t); 104#endif /* PAX_ASLR */ 105 106#ifdef PAX_MPROTECT 107static int pax_mprotect_enabled = 1; 108static int pax_mprotect_global = PAX_MPROTECT; 109static bool pax_mprotect_elf_flags_active(uint32_t); 110#endif /* PAX_MPROTECT */ 111 112#ifdef PAX_SEGVGUARD 113#ifndef PAX_SEGVGUARD_EXPIRY 114#define PAX_SEGVGUARD_EXPIRY (2 * 60) 115#endif 116#ifndef PAX_SEGVGUARD_SUSPENSION 117#define PAX_SEGVGUARD_SUSPENSION (10 * 60) 118#endif 119#ifndef PAX_SEGVGUARD_MAXCRASHES 120#define PAX_SEGVGUARD_MAXCRASHES 5 121#endif 122 123static int pax_segvguard_enabled = 1; 124static int pax_segvguard_global = PAX_SEGVGUARD; 125static int pax_segvguard_expiry = PAX_SEGVGUARD_EXPIRY; 126static int pax_segvguard_suspension = PAX_SEGVGUARD_SUSPENSION; 127static int pax_segvguard_maxcrashes = PAX_SEGVGUARD_MAXCRASHES; 128 129static fileassoc_t segvguard_id; 130 131struct pax_segvguard_uid_entry { 132 uid_t sue_uid; 133 size_t sue_ncrashes; 134 time_t sue_expiry; 135 time_t sue_suspended; 136 LIST_ENTRY(pax_segvguard_uid_entry) sue_list; 137}; 138 139struct pax_segvguard_entry { 140 LIST_HEAD(, pax_segvguard_uid_entry) segv_uids; 141}; 142 143static bool pax_segvguard_elf_flags_active(uint32_t); 144static void pax_segvguard_cleanup_cb(void *); 145#endif /* PAX_SEGVGUARD */ 146 147SYSCTL_SETUP(sysctl_security_pax_setup, "sysctl security.pax setup") 148{ 149 const struct sysctlnode *rnode = NULL, *cnode; 150 151 sysctl_createv(clog, 0, NULL, &rnode, 152 CTLFLAG_PERMANENT, 153 CTLTYPE_NODE, "pax", 154 SYSCTL_DESCR("PaX (exploit mitigation) features."), 155 NULL, 0, NULL, 0, 156 CTL_SECURITY, CTL_CREATE, CTL_EOL); 157 158 cnode = rnode; 159 160#ifdef PAX_MPROTECT 161 rnode = cnode; 162 sysctl_createv(clog, 0, &rnode, &rnode, 163 CTLFLAG_PERMANENT, 164 CTLTYPE_NODE, "mprotect", 165 SYSCTL_DESCR("mprotect(2) W^X restrictions."), 166 NULL, 0, NULL, 0, 167 CTL_CREATE, CTL_EOL); 168 sysctl_createv(clog, 0, &rnode, NULL, 169 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 170 CTLTYPE_INT, "enabled", 171 SYSCTL_DESCR("Restrictions enabled."), 172 NULL, 0, &pax_mprotect_enabled, 0, 173 CTL_CREATE, CTL_EOL); 174 sysctl_createv(clog, 0, &rnode, NULL, 175 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 176 CTLTYPE_INT, "global", 177 SYSCTL_DESCR("When enabled, unless explicitly " 178 "specified, apply restrictions to " 179 "all processes."), 180 NULL, 0, &pax_mprotect_global, 0, 181 CTL_CREATE, CTL_EOL); 182#endif /* PAX_MPROTECT */ 183 184#ifdef PAX_SEGVGUARD 185 rnode = cnode; 186 sysctl_createv(clog, 0, &rnode, &rnode, 187 CTLFLAG_PERMANENT, 188 CTLTYPE_NODE, "segvguard", 189 SYSCTL_DESCR("PaX segvguard."), 190 NULL, 0, NULL, 0, 191 CTL_CREATE, CTL_EOL); 192 sysctl_createv(clog, 0, &rnode, NULL, 193 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 194 CTLTYPE_INT, "enabled", 195 SYSCTL_DESCR("segvguard enabled."), 196 NULL, 0, &pax_segvguard_enabled, 0, 197 CTL_CREATE, CTL_EOL); 198 sysctl_createv(clog, 0, &rnode, NULL, 199 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 200 CTLTYPE_INT, "global", 201 SYSCTL_DESCR("segvguard all programs."), 202 NULL, 0, &pax_segvguard_global, 0, 203 CTL_CREATE, CTL_EOL); 204 sysctl_createv(clog, 0, &rnode, NULL, 205 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 206 CTLTYPE_INT, "expiry_timeout", 207 SYSCTL_DESCR("Entry expiry timeout (in seconds)."), 208 NULL, 0, &pax_segvguard_expiry, 0, 209 CTL_CREATE, CTL_EOL); 210 sysctl_createv(clog, 0, &rnode, NULL, 211 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 212 CTLTYPE_INT, "suspend_timeout", 213 SYSCTL_DESCR("Entry suspension timeout (in seconds)."), 214 NULL, 0, &pax_segvguard_suspension, 0, 215 CTL_CREATE, CTL_EOL); 216 sysctl_createv(clog, 0, &rnode, NULL, 217 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 218 CTLTYPE_INT, "max_crashes", 219 SYSCTL_DESCR("Max number of crashes before expiry."), 220 NULL, 0, &pax_segvguard_maxcrashes, 0, 221 CTL_CREATE, CTL_EOL); 222#endif /* PAX_SEGVGUARD */ 223 224#ifdef PAX_ASLR 225 rnode = cnode; 226 sysctl_createv(clog, 0, &rnode, &rnode, 227 CTLFLAG_PERMANENT, 228 CTLTYPE_NODE, "aslr", 229 SYSCTL_DESCR("Address Space Layout Randomization."), 230 NULL, 0, NULL, 0, 231 CTL_CREATE, CTL_EOL); 232 sysctl_createv(clog, 0, &rnode, NULL, 233 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 234 CTLTYPE_INT, "enabled", 235 SYSCTL_DESCR("Restrictions enabled."), 236 NULL, 0, &pax_aslr_enabled, 0, 237 CTL_CREATE, CTL_EOL); 238 sysctl_createv(clog, 0, &rnode, NULL, 239 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 240 CTLTYPE_INT, "global", 241 SYSCTL_DESCR("When enabled, unless explicitly " 242 "specified, apply to all processes."), 243 NULL, 0, &pax_aslr_global, 0, 244 CTL_CREATE, CTL_EOL); 245 sysctl_createv(clog, 0, &rnode, NULL, 246 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE, 247 CTLTYPE_INT, "mmap_len", 248 SYSCTL_DESCR("Number of bits randomized for " 249 "mmap(2) calls."), 250 NULL, PAX_ASLR_DELTA_MMAP_LEN, NULL, 0, 251 CTL_CREATE, CTL_EOL); 252 sysctl_createv(clog, 0, &rnode, NULL, 253 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE, 254 CTLTYPE_INT, "stack_len", 255 SYSCTL_DESCR("Number of bits randomized for " 256 "the stack."), 257 NULL, PAX_ASLR_DELTA_STACK_LEN, NULL, 0, 258 CTL_CREATE, CTL_EOL); 259 sysctl_createv(clog, 0, &rnode, NULL, 260 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE, 261 CTLTYPE_INT, "exec_len", 262 SYSCTL_DESCR("Number of bits randomized for " 263 "the PIE exec base."), 264 NULL, PAX_ASLR_DELTA_EXEC_LEN, NULL, 0, 265 CTL_CREATE, CTL_EOL); 266 267#endif /* PAX_ASLR */ 268} 269 270/* 271 * Initialize PaX. 272 */ 273void 274pax_init(void) 275{ 276#ifdef PAX_SEGVGUARD 277 int error; 278 279 error = fileassoc_register("segvguard", pax_segvguard_cleanup_cb, 280 &segvguard_id); 281 if (error) { 282 panic("pax_init: segvguard_id: error=%d\n", error); 283 } 284#endif /* PAX_SEGVGUARD */ 285} 286 287void 288pax_setup_elf_flags(struct exec_package *epp, uint32_t elf_flags) 289{ 290 uint32_t flags = 0; 291 292#ifdef PAX_ASLR 293 if (pax_aslr_elf_flags_active(elf_flags)) { 294 flags |= P_PAX_ASLR; 295 } 296#endif 297#ifdef PAX_MPROTECT 298 if (pax_mprotect_elf_flags_active(elf_flags)) { 299 flags |= P_PAX_MPROTECT; 300 } 301#endif 302#ifdef PAX_SEGVGUARD 303 if (pax_segvguard_elf_flags_active(elf_flags)) { 304 flags |= P_PAX_GUARD; 305 } 306#endif 307 308 epp->ep_pax_flags = flags; 309} 310 311#if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD) || defined(PAX_ASLR) 312static inline bool 313pax_flags_active(uint32_t flags, uint32_t opt) 314{ 315 if (!(flags & opt)) 316 return false; 317 return true; 318} 319#endif /* PAX_MPROTECT || PAX_SEGVGUARD || PAX_ASLR */ 320 321#ifdef PAX_MPROTECT 322static bool 323pax_mprotect_elf_flags_active(uint32_t flags) 324{ 325 if (!pax_mprotect_enabled) 326 return false; 327 if (pax_mprotect_global && (flags & ELF_NOTE_PAX_NOMPROTECT) != 0) { 328 /* Mprotect explicitly disabled */ 329 return false; 330 } 331 if (!pax_mprotect_global && (flags & ELF_NOTE_PAX_MPROTECT) == 0) { 332 /* Mprotect not requested */ 333 return false; 334 } 335 return true; 336} 337 338void 339pax_mprotect(struct lwp *l, vm_prot_t *prot, vm_prot_t *maxprot) 340{ 341 uint32_t flags; 342 343 flags = l->l_proc->p_pax; 344 if (!pax_flags_active(flags, P_PAX_MPROTECT)) 345 return; 346 347 if ((*prot & (VM_PROT_WRITE|VM_PROT_EXECUTE)) != VM_PROT_EXECUTE) { 348 *prot &= ~VM_PROT_EXECUTE; 349 *maxprot &= ~VM_PROT_EXECUTE; 350 } else { 351 *prot &= ~VM_PROT_WRITE; 352 *maxprot &= ~VM_PROT_WRITE; 353 } 354} 355#endif /* PAX_MPROTECT */ 356 357#ifdef PAX_ASLR 358static bool 359pax_aslr_elf_flags_active(uint32_t flags) 360{ 361 if (!pax_aslr_enabled) 362 return false; 363 if (pax_aslr_global && (flags & ELF_NOTE_PAX_NOASLR) != 0) { 364 /* ASLR explicitly disabled */ 365 return false; 366 } 367 if (!pax_aslr_global && (flags & ELF_NOTE_PAX_ASLR) == 0) { 368 /* ASLR not requested */ 369 return false; 370 } 371 return true; 372} 373 374bool 375pax_aslr_epp_active(struct exec_package *epp) 376{ 377 return pax_flags_active(epp->ep_pax_flags, P_PAX_ASLR); 378} 379 380bool 381pax_aslr_active(struct lwp *l) 382{ 383 return pax_flags_active(l->l_proc->p_pax, P_PAX_ASLR); 384} 385 386void 387pax_aslr_init_vm(struct lwp *l, struct vmspace *vm) 388{ 389 if (!pax_aslr_active(l)) 390 return; 391 392 vm->vm_aslr_delta_mmap = PAX_ASLR_DELTA(cprng_fast32(), 393 PAX_ASLR_DELTA_MMAP_LSB, PAX_ASLR_DELTA_MMAP_LEN); 394} 395 396void 397pax_aslr_mmap(struct lwp *l, vaddr_t *addr, vaddr_t orig_addr, int f) 398{ 399 if (!pax_aslr_active(l)) 400 return; 401 402 if (!(f & MAP_FIXED) && ((orig_addr == 0) || !(f & MAP_ANON))) { 403 PAX_DPRINTF("applying to 0x%lx orig_addr=0x%lx f=%x", 404 (unsigned long)*addr, (unsigned long)orig_addr, f); 405 if (!(l->l_proc->p_vmspace->vm_map.flags & VM_MAP_TOPDOWN)) 406 *addr += l->l_proc->p_vmspace->vm_aslr_delta_mmap; 407 else 408 *addr -= l->l_proc->p_vmspace->vm_aslr_delta_mmap; 409 PAX_DPRINTF("result 0x%lx", *addr); 410 } else { 411 PAX_DPRINTF("not applying to 0x%lx orig_addr=0x%lx f=%x", 412 (unsigned long)*addr, (unsigned long)orig_addr, f); 413 } 414} 415 416void 417pax_aslr_stack(struct exec_package *epp, u_long *max_stack_size) 418{ 419 if (!pax_aslr_epp_active(epp)) 420 return; 421 422 u_long d = PAX_ASLR_DELTA(cprng_fast32(), 423 PAX_ASLR_DELTA_STACK_LSB, 424 PAX_ASLR_DELTA_STACK_LEN); 425 PAX_DPRINTF("stack 0x%lx d=0x%lx 0x%lx", 426 epp->ep_minsaddr, d, epp->ep_minsaddr - d); 427 epp->ep_minsaddr -= d; 428 *max_stack_size -= d; 429 if (epp->ep_ssize > *max_stack_size) 430 epp->ep_ssize = *max_stack_size; 431} 432#endif /* PAX_ASLR */ 433 434#ifdef PAX_SEGVGUARD 435static bool 436pax_segvguard_elf_flags_active(uint32_t flags) 437{ 438 if (!pax_segvguard_enabled) 439 return false; 440 if (pax_segvguard_global && (flags & ELF_NOTE_PAX_NOGUARD) != 0) { 441 /* Segvguard explicitly disabled */ 442 return false; 443 } 444 if (!pax_segvguard_global && (flags & ELF_NOTE_PAX_GUARD) == 0) { 445 /* Segvguard not requested */ 446 return false; 447 } 448 return true; 449} 450 451static void 452pax_segvguard_cleanup_cb(void *v) 453{ 454 struct pax_segvguard_entry *p = v; 455 struct pax_segvguard_uid_entry *up; 456 457 if (p == NULL) { 458 return; 459 } 460 while ((up = LIST_FIRST(&p->segv_uids)) != NULL) { 461 LIST_REMOVE(up, sue_list); 462 kmem_free(up, sizeof(*up)); 463 } 464 kmem_free(p, sizeof(*p)); 465} 466 467/* 468 * Called when a process of image vp generated a segfault. 469 */ 470int 471pax_segvguard(struct lwp *l, struct vnode *vp, const char *name, 472 bool crashed) 473{ 474 struct pax_segvguard_entry *p; 475 struct pax_segvguard_uid_entry *up; 476 struct timeval tv; 477 uid_t uid; 478 uint32_t flags; 479 bool have_uid; 480 481 flags = l->l_proc->p_pax; 482 if (!pax_flags_active(flags, P_PAX_GUARD)) 483 return 0; 484 485 if (vp == NULL) 486 return EFAULT; 487 488 /* Check if we already monitor the file. */ 489 p = fileassoc_lookup(vp, segvguard_id); 490 491 /* Fast-path if starting a program we don't know. */ 492 if (p == NULL && !crashed) 493 return 0; 494 495 microtime(&tv); 496 497 /* 498 * If a program we don't know crashed, we need to create a new entry 499 * for it. 500 */ 501 if (p == NULL) { 502 p = kmem_alloc(sizeof(*p), KM_SLEEP); 503 fileassoc_add(vp, segvguard_id, p); 504 LIST_INIT(&p->segv_uids); 505 506 /* 507 * Initialize a new entry with "crashes so far" of 1. 508 * The expiry time is when we purge the entry if it didn't 509 * reach the limit. 510 */ 511 up = kmem_alloc(sizeof(*up), KM_SLEEP); 512 up->sue_uid = kauth_cred_getuid(l->l_cred); 513 up->sue_ncrashes = 1; 514 up->sue_expiry = tv.tv_sec + pax_segvguard_expiry; 515 up->sue_suspended = 0; 516 LIST_INSERT_HEAD(&p->segv_uids, up, sue_list); 517 return 0; 518 } 519 520 /* 521 * A program we "know" either executed or crashed again. 522 * See if it's a culprit we're familiar with. 523 */ 524 uid = kauth_cred_getuid(l->l_cred); 525 have_uid = false; 526 LIST_FOREACH(up, &p->segv_uids, sue_list) { 527 if (up->sue_uid == uid) { 528 have_uid = true; 529 break; 530 } 531 } 532 533 /* 534 * It's someone else. Add an entry for him if we crashed. 535 */ 536 if (!have_uid) { 537 if (crashed) { 538 up = kmem_alloc(sizeof(*up), KM_SLEEP); 539 up->sue_uid = uid; 540 up->sue_ncrashes = 1; 541 up->sue_expiry = tv.tv_sec + pax_segvguard_expiry; 542 up->sue_suspended = 0; 543 LIST_INSERT_HEAD(&p->segv_uids, up, sue_list); 544 } 545 return 0; 546 } 547 548 if (crashed) { 549 /* Check if timer on previous crashes expired first. */ 550 if (up->sue_expiry < tv.tv_sec) { 551 log(LOG_INFO, "PaX Segvguard: [%s] Suspension" 552 " expired.\n", name ? name : "unknown"); 553 up->sue_ncrashes = 1; 554 up->sue_expiry = tv.tv_sec + pax_segvguard_expiry; 555 up->sue_suspended = 0; 556 return 0; 557 } 558 559 up->sue_ncrashes++; 560 561 if (up->sue_ncrashes >= pax_segvguard_maxcrashes) { 562 log(LOG_ALERT, "PaX Segvguard: [%s] Suspending " 563 "execution for %d seconds after %zu crashes.\n", 564 name ? name : "unknown", pax_segvguard_suspension, 565 up->sue_ncrashes); 566 567 /* Suspend this program for a while. */ 568 up->sue_suspended = tv.tv_sec + pax_segvguard_suspension; 569 up->sue_ncrashes = 0; 570 up->sue_expiry = 0; 571 } 572 } else { 573 /* Are we supposed to be suspended? */ 574 if (up->sue_suspended > tv.tv_sec) { 575 log(LOG_ALERT, "PaX Segvguard: [%s] Preventing " 576 "execution due to repeated segfaults.\n", name ? 577 name : "unknown"); 578 return EPERM; 579 } 580 } 581 582 return 0; 583} 584#endif /* PAX_SEGVGUARD */ 585