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