kern_pax.c revision 1.34
1/* $NetBSD: kern_pax.c,v 1.34 2016/03/19 18:56:37 christos 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.34 2016/03/19 18:56:37 christos Exp $"); 61 62#include "opt_pax.h" 63 64#include <sys/param.h> 65#include <sys/proc.h> 66#include <sys/exec.h> 67#include <sys/exec_elf.h> 68#include <sys/pax.h> 69#include <sys/sysctl.h> 70#include <sys/kmem.h> 71#include <sys/mman.h> 72#include <sys/fileassoc.h> 73#include <sys/syslog.h> 74#include <sys/vnode.h> 75#include <sys/queue.h> 76#include <sys/kauth.h> 77#include <sys/cprng.h> 78 79#ifdef PAX_ASLR_DEBUG 80#define PAX_DPRINTF(_fmt, args...) \ 81 do if (pax_aslr_debug) uprintf("%s: " _fmt "\n", __func__, ##args); \ 82 while (/*CONSTCOND*/0) 83#else 84#define PAX_DPRINTF(_fmt, args...) do {} while (/*CONSTCOND*/0) 85#endif 86 87#ifdef PAX_ASLR 88#include <sys/mman.h> 89 90int pax_aslr_enabled = 1; 91int pax_aslr_global = PAX_ASLR; 92 93#ifndef PAX_ASLR_DELTA_MMAP_LSB 94#define PAX_ASLR_DELTA_MMAP_LSB PGSHIFT 95#endif 96#ifndef PAX_ASLR_DELTA_MMAP_LEN 97#define PAX_ASLR_DELTA_MMAP_LEN ((sizeof(void *) * NBBY) / 2) 98#endif 99#ifndef PAX_ASLR_DELTA_STACK_LSB 100#define PAX_ASLR_DELTA_STACK_LSB PGSHIFT 101#endif 102#ifndef PAX_ASLR_DELTA_STACK_LEN 103#define PAX_ASLR_DELTA_STACK_LEN 12 104#endif 105 106static bool pax_aslr_elf_flags_active(uint32_t); 107#endif /* PAX_ASLR */ 108 109#ifdef PAX_MPROTECT 110static int pax_mprotect_enabled = 1; 111static int pax_mprotect_global = PAX_MPROTECT; 112static bool pax_mprotect_elf_flags_active(uint32_t); 113#endif /* PAX_MPROTECT */ 114 115#ifdef PAX_SEGVGUARD 116#ifndef PAX_SEGVGUARD_EXPIRY 117#define PAX_SEGVGUARD_EXPIRY (2 * 60) 118#endif 119#ifndef PAX_SEGVGUARD_SUSPENSION 120#define PAX_SEGVGUARD_SUSPENSION (10 * 60) 121#endif 122#ifndef PAX_SEGVGUARD_MAXCRASHES 123#define PAX_SEGVGUARD_MAXCRASHES 5 124#endif 125 126#ifdef PAX_ASLR_DEBUG 127int pax_aslr_debug; 128#endif 129 130static int pax_segvguard_enabled = 1; 131static int pax_segvguard_global = PAX_SEGVGUARD; 132static int pax_segvguard_expiry = PAX_SEGVGUARD_EXPIRY; 133static int pax_segvguard_suspension = PAX_SEGVGUARD_SUSPENSION; 134static int pax_segvguard_maxcrashes = PAX_SEGVGUARD_MAXCRASHES; 135 136static fileassoc_t segvguard_id; 137 138struct pax_segvguard_uid_entry { 139 uid_t sue_uid; 140 size_t sue_ncrashes; 141 time_t sue_expiry; 142 time_t sue_suspended; 143 LIST_ENTRY(pax_segvguard_uid_entry) sue_list; 144}; 145 146struct pax_segvguard_entry { 147 LIST_HEAD(, pax_segvguard_uid_entry) segv_uids; 148}; 149 150static bool pax_segvguard_elf_flags_active(uint32_t); 151static void pax_segvguard_cleanup_cb(void *); 152#endif /* PAX_SEGVGUARD */ 153 154SYSCTL_SETUP(sysctl_security_pax_setup, "sysctl security.pax setup") 155{ 156 const struct sysctlnode *rnode = NULL, *cnode; 157 158 sysctl_createv(clog, 0, NULL, &rnode, 159 CTLFLAG_PERMANENT, 160 CTLTYPE_NODE, "pax", 161 SYSCTL_DESCR("PaX (exploit mitigation) features."), 162 NULL, 0, NULL, 0, 163 CTL_SECURITY, CTL_CREATE, CTL_EOL); 164 165 cnode = rnode; 166 167#ifdef PAX_MPROTECT 168 rnode = cnode; 169 sysctl_createv(clog, 0, &rnode, &rnode, 170 CTLFLAG_PERMANENT, 171 CTLTYPE_NODE, "mprotect", 172 SYSCTL_DESCR("mprotect(2) W^X restrictions."), 173 NULL, 0, NULL, 0, 174 CTL_CREATE, CTL_EOL); 175 sysctl_createv(clog, 0, &rnode, NULL, 176 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 177 CTLTYPE_INT, "enabled", 178 SYSCTL_DESCR("Restrictions enabled."), 179 NULL, 0, &pax_mprotect_enabled, 0, 180 CTL_CREATE, CTL_EOL); 181 sysctl_createv(clog, 0, &rnode, NULL, 182 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 183 CTLTYPE_INT, "global", 184 SYSCTL_DESCR("When enabled, unless explicitly " 185 "specified, apply restrictions to " 186 "all processes."), 187 NULL, 0, &pax_mprotect_global, 0, 188 CTL_CREATE, CTL_EOL); 189#endif /* PAX_MPROTECT */ 190 191#ifdef PAX_SEGVGUARD 192 rnode = cnode; 193 sysctl_createv(clog, 0, &rnode, &rnode, 194 CTLFLAG_PERMANENT, 195 CTLTYPE_NODE, "segvguard", 196 SYSCTL_DESCR("PaX segvguard."), 197 NULL, 0, NULL, 0, 198 CTL_CREATE, CTL_EOL); 199 sysctl_createv(clog, 0, &rnode, NULL, 200 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 201 CTLTYPE_INT, "enabled", 202 SYSCTL_DESCR("segvguard enabled."), 203 NULL, 0, &pax_segvguard_enabled, 0, 204 CTL_CREATE, CTL_EOL); 205 sysctl_createv(clog, 0, &rnode, NULL, 206 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 207 CTLTYPE_INT, "global", 208 SYSCTL_DESCR("segvguard all programs."), 209 NULL, 0, &pax_segvguard_global, 0, 210 CTL_CREATE, CTL_EOL); 211 sysctl_createv(clog, 0, &rnode, NULL, 212 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 213 CTLTYPE_INT, "expiry_timeout", 214 SYSCTL_DESCR("Entry expiry timeout (in seconds)."), 215 NULL, 0, &pax_segvguard_expiry, 0, 216 CTL_CREATE, CTL_EOL); 217 sysctl_createv(clog, 0, &rnode, NULL, 218 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 219 CTLTYPE_INT, "suspend_timeout", 220 SYSCTL_DESCR("Entry suspension timeout (in seconds)."), 221 NULL, 0, &pax_segvguard_suspension, 0, 222 CTL_CREATE, CTL_EOL); 223 sysctl_createv(clog, 0, &rnode, NULL, 224 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 225 CTLTYPE_INT, "max_crashes", 226 SYSCTL_DESCR("Max number of crashes before expiry."), 227 NULL, 0, &pax_segvguard_maxcrashes, 0, 228 CTL_CREATE, CTL_EOL); 229#endif /* PAX_SEGVGUARD */ 230 231#ifdef PAX_ASLR 232 rnode = cnode; 233 sysctl_createv(clog, 0, &rnode, &rnode, 234 CTLFLAG_PERMANENT, 235 CTLTYPE_NODE, "aslr", 236 SYSCTL_DESCR("Address Space Layout Randomization."), 237 NULL, 0, NULL, 0, 238 CTL_CREATE, CTL_EOL); 239 sysctl_createv(clog, 0, &rnode, NULL, 240 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 241 CTLTYPE_INT, "enabled", 242 SYSCTL_DESCR("Restrictions enabled."), 243 NULL, 0, &pax_aslr_enabled, 0, 244 CTL_CREATE, CTL_EOL); 245 sysctl_createv(clog, 0, &rnode, NULL, 246 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 247 CTLTYPE_INT, "global", 248 SYSCTL_DESCR("When enabled, unless explicitly " 249 "specified, apply to all processes."), 250 NULL, 0, &pax_aslr_global, 0, 251 CTL_CREATE, CTL_EOL); 252#ifdef PAX_ASLR_DEBUG 253 sysctl_createv(clog, 0, &rnode, NULL, 254 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 255 CTLTYPE_INT, "debug", 256 SYSCTL_DESCR("Pring ASLR selected addresses."), 257 NULL, 0, &pax_aslr_debug, 0, 258 CTL_CREATE, CTL_EOL); 259#endif 260 sysctl_createv(clog, 0, &rnode, NULL, 261 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE, 262 CTLTYPE_INT, "mmap_len", 263 SYSCTL_DESCR("Number of bits randomized for " 264 "mmap(2) calls."), 265 NULL, PAX_ASLR_DELTA_MMAP_LEN, NULL, 0, 266 CTL_CREATE, CTL_EOL); 267 sysctl_createv(clog, 0, &rnode, NULL, 268 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE, 269 CTLTYPE_INT, "stack_len", 270 SYSCTL_DESCR("Number of bits randomized for " 271 "the stack."), 272 NULL, PAX_ASLR_DELTA_STACK_LEN, NULL, 0, 273 CTL_CREATE, CTL_EOL); 274 sysctl_createv(clog, 0, &rnode, NULL, 275 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE, 276 CTLTYPE_INT, "exec_len", 277 SYSCTL_DESCR("Number of bits randomized for " 278 "the PIE exec base."), 279 NULL, PAX_ASLR_DELTA_EXEC_LEN, NULL, 0, 280 CTL_CREATE, CTL_EOL); 281 282#endif /* PAX_ASLR */ 283} 284 285/* 286 * Initialize PaX. 287 */ 288void 289pax_init(void) 290{ 291#ifdef PAX_SEGVGUARD 292 int error; 293 294 error = fileassoc_register("segvguard", pax_segvguard_cleanup_cb, 295 &segvguard_id); 296 if (error) { 297 panic("pax_init: segvguard_id: error=%d\n", error); 298 } 299#endif /* PAX_SEGVGUARD */ 300} 301 302void 303pax_setup_elf_flags(struct exec_package *epp, uint32_t elf_flags) 304{ 305 uint32_t flags = 0; 306 307#ifdef PAX_ASLR 308 if (pax_aslr_elf_flags_active(elf_flags)) { 309 flags |= P_PAX_ASLR; 310 } 311#endif 312#ifdef PAX_MPROTECT 313 if (pax_mprotect_elf_flags_active(elf_flags)) { 314 flags |= P_PAX_MPROTECT; 315 } 316#endif 317#ifdef PAX_SEGVGUARD 318 if (pax_segvguard_elf_flags_active(elf_flags)) { 319 flags |= P_PAX_GUARD; 320 } 321#endif 322 323 epp->ep_pax_flags = flags; 324} 325 326#if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD) || defined(PAX_ASLR) 327static inline bool 328pax_flags_active(uint32_t flags, uint32_t opt) 329{ 330 if (!(flags & opt)) 331 return false; 332 return true; 333} 334#endif /* PAX_MPROTECT || PAX_SEGVGUARD || PAX_ASLR */ 335 336#ifdef PAX_MPROTECT 337static bool 338pax_mprotect_elf_flags_active(uint32_t flags) 339{ 340 if (!pax_mprotect_enabled) 341 return false; 342 if (pax_mprotect_global && (flags & ELF_NOTE_PAX_NOMPROTECT) != 0) { 343 /* Mprotect explicitly disabled */ 344 return false; 345 } 346 if (!pax_mprotect_global && (flags & ELF_NOTE_PAX_MPROTECT) == 0) { 347 /* Mprotect not requested */ 348 return false; 349 } 350 return true; 351} 352 353void 354pax_mprotect(struct lwp *l, vm_prot_t *prot, vm_prot_t *maxprot) 355{ 356 uint32_t flags; 357 358 flags = l->l_proc->p_pax; 359 if (!pax_flags_active(flags, P_PAX_MPROTECT)) 360 return; 361 362 if ((*prot & (VM_PROT_WRITE|VM_PROT_EXECUTE)) != VM_PROT_EXECUTE) { 363 *prot &= ~VM_PROT_EXECUTE; 364 *maxprot &= ~VM_PROT_EXECUTE; 365 } else { 366 *prot &= ~VM_PROT_WRITE; 367 *maxprot &= ~VM_PROT_WRITE; 368 } 369} 370#endif /* PAX_MPROTECT */ 371 372#ifdef PAX_ASLR 373static bool 374pax_aslr_elf_flags_active(uint32_t flags) 375{ 376 if (!pax_aslr_enabled) 377 return false; 378 if (pax_aslr_global && (flags & ELF_NOTE_PAX_NOASLR) != 0) { 379 /* ASLR explicitly disabled */ 380 return false; 381 } 382 if (!pax_aslr_global && (flags & ELF_NOTE_PAX_ASLR) == 0) { 383 /* ASLR not requested */ 384 return false; 385 } 386 return true; 387} 388 389bool 390pax_aslr_epp_active(struct exec_package *epp) 391{ 392 return pax_flags_active(epp->ep_pax_flags, P_PAX_ASLR); 393} 394 395bool 396pax_aslr_active(struct lwp *l) 397{ 398 return pax_flags_active(l->l_proc->p_pax, P_PAX_ASLR); 399} 400 401void 402pax_aslr_init_vm(struct lwp *l, struct vmspace *vm) 403{ 404 if (!pax_aslr_active(l)) 405 return; 406 407 vm->vm_aslr_delta_mmap = PAX_ASLR_DELTA(cprng_fast32(), 408 PAX_ASLR_DELTA_MMAP_LSB, PAX_ASLR_DELTA_MMAP_LEN); 409 PAX_DPRINTF("delta_mmap=%#jx", vm->vm_aslr_delta_mmap); 410} 411 412void 413pax_aslr_mmap(struct lwp *l, vaddr_t *addr, vaddr_t orig_addr, int f) 414{ 415 if (!pax_aslr_active(l)) 416 return; 417#ifdef PAX_ASLR_DEBUG 418 char buf[256]; 419 if (pax_aslr_debug) 420 snprintb(buf, sizeof(buf), MAP_FMT, f); 421 else 422 buf[0] = '\0'; 423#endif 424 425 if (!(f & MAP_FIXED) && ((orig_addr == 0) || !(f & MAP_ANON))) { 426 PAX_DPRINTF("applying to %#jx orig_addr=%#jx f=%s", 427 (uintmax_t)*addr, (uintmax_t)orig_addr, buf); 428 if (!(l->l_proc->p_vmspace->vm_map.flags & VM_MAP_TOPDOWN)) 429 *addr += l->l_proc->p_vmspace->vm_aslr_delta_mmap; 430 else 431 *addr -= l->l_proc->p_vmspace->vm_aslr_delta_mmap; 432 PAX_DPRINTF("result %#jx", (uintmax_t)*addr); 433 } else { 434 PAX_DPRINTF("not applying to %#jx orig_addr=%#jx f=%s", 435 (uintmax_t)*addr, (uintmax_t)orig_addr, buf); 436 } 437} 438 439void 440pax_aslr_stack(struct exec_package *epp, u_long *max_stack_size) 441{ 442 if (!pax_aslr_epp_active(epp)) 443 return; 444 445 u_long d = PAX_ASLR_DELTA(cprng_fast32(), 446 PAX_ASLR_DELTA_STACK_LSB, 447 PAX_ASLR_DELTA_STACK_LEN); 448 PAX_DPRINTF("stack %#jx delta=%#lx diff=%lx", 449 (uintmax_t)epp->ep_minsaddr, d, epp->ep_minsaddr - d); 450 epp->ep_minsaddr -= d; 451 *max_stack_size -= d; 452 if (epp->ep_ssize > *max_stack_size) 453 epp->ep_ssize = *max_stack_size; 454} 455#endif /* PAX_ASLR */ 456 457#ifdef PAX_SEGVGUARD 458static bool 459pax_segvguard_elf_flags_active(uint32_t flags) 460{ 461 if (!pax_segvguard_enabled) 462 return false; 463 if (pax_segvguard_global && (flags & ELF_NOTE_PAX_NOGUARD) != 0) { 464 /* Segvguard explicitly disabled */ 465 return false; 466 } 467 if (!pax_segvguard_global && (flags & ELF_NOTE_PAX_GUARD) == 0) { 468 /* Segvguard not requested */ 469 return false; 470 } 471 return true; 472} 473 474static void 475pax_segvguard_cleanup_cb(void *v) 476{ 477 struct pax_segvguard_entry *p = v; 478 struct pax_segvguard_uid_entry *up; 479 480 if (p == NULL) { 481 return; 482 } 483 while ((up = LIST_FIRST(&p->segv_uids)) != NULL) { 484 LIST_REMOVE(up, sue_list); 485 kmem_free(up, sizeof(*up)); 486 } 487 kmem_free(p, sizeof(*p)); 488} 489 490/* 491 * Called when a process of image vp generated a segfault. 492 */ 493int 494pax_segvguard(struct lwp *l, struct vnode *vp, const char *name, 495 bool crashed) 496{ 497 struct pax_segvguard_entry *p; 498 struct pax_segvguard_uid_entry *up; 499 struct timeval tv; 500 uid_t uid; 501 uint32_t flags; 502 bool have_uid; 503 504 flags = l->l_proc->p_pax; 505 if (!pax_flags_active(flags, P_PAX_GUARD)) 506 return 0; 507 508 if (vp == NULL) 509 return EFAULT; 510 511 /* Check if we already monitor the file. */ 512 p = fileassoc_lookup(vp, segvguard_id); 513 514 /* Fast-path if starting a program we don't know. */ 515 if (p == NULL && !crashed) 516 return 0; 517 518 microtime(&tv); 519 520 /* 521 * If a program we don't know crashed, we need to create a new entry 522 * for it. 523 */ 524 if (p == NULL) { 525 p = kmem_alloc(sizeof(*p), KM_SLEEP); 526 fileassoc_add(vp, segvguard_id, p); 527 LIST_INIT(&p->segv_uids); 528 529 /* 530 * Initialize a new entry with "crashes so far" of 1. 531 * The expiry time is when we purge the entry if it didn't 532 * reach the limit. 533 */ 534 up = kmem_alloc(sizeof(*up), KM_SLEEP); 535 up->sue_uid = kauth_cred_getuid(l->l_cred); 536 up->sue_ncrashes = 1; 537 up->sue_expiry = tv.tv_sec + pax_segvguard_expiry; 538 up->sue_suspended = 0; 539 LIST_INSERT_HEAD(&p->segv_uids, up, sue_list); 540 return 0; 541 } 542 543 /* 544 * A program we "know" either executed or crashed again. 545 * See if it's a culprit we're familiar with. 546 */ 547 uid = kauth_cred_getuid(l->l_cred); 548 have_uid = false; 549 LIST_FOREACH(up, &p->segv_uids, sue_list) { 550 if (up->sue_uid == uid) { 551 have_uid = true; 552 break; 553 } 554 } 555 556 /* 557 * It's someone else. Add an entry for him if we crashed. 558 */ 559 if (!have_uid) { 560 if (crashed) { 561 up = kmem_alloc(sizeof(*up), KM_SLEEP); 562 up->sue_uid = uid; 563 up->sue_ncrashes = 1; 564 up->sue_expiry = tv.tv_sec + pax_segvguard_expiry; 565 up->sue_suspended = 0; 566 LIST_INSERT_HEAD(&p->segv_uids, up, sue_list); 567 } 568 return 0; 569 } 570 571 if (crashed) { 572 /* Check if timer on previous crashes expired first. */ 573 if (up->sue_expiry < tv.tv_sec) { 574 log(LOG_INFO, "PaX Segvguard: [%s] Suspension" 575 " expired.\n", name ? name : "unknown"); 576 up->sue_ncrashes = 1; 577 up->sue_expiry = tv.tv_sec + pax_segvguard_expiry; 578 up->sue_suspended = 0; 579 return 0; 580 } 581 582 up->sue_ncrashes++; 583 584 if (up->sue_ncrashes >= pax_segvguard_maxcrashes) { 585 log(LOG_ALERT, "PaX Segvguard: [%s] Suspending " 586 "execution for %d seconds after %zu crashes.\n", 587 name ? name : "unknown", pax_segvguard_suspension, 588 up->sue_ncrashes); 589 590 /* Suspend this program for a while. */ 591 up->sue_suspended = tv.tv_sec + pax_segvguard_suspension; 592 up->sue_ncrashes = 0; 593 up->sue_expiry = 0; 594 } 595 } else { 596 /* Are we supposed to be suspended? */ 597 if (up->sue_suspended > tv.tv_sec) { 598 log(LOG_ALERT, "PaX Segvguard: [%s] Preventing " 599 "execution due to repeated segfaults.\n", name ? 600 name : "unknown"); 601 return EPERM; 602 } 603 } 604 605 return 0; 606} 607#endif /* PAX_SEGVGUARD */ 608