kern_pax.c revision 1.48
1/* $NetBSD: kern_pax.c,v 1.48 2016/05/22 01:09:09 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.48 2016/05/22 01:09:09 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/bitops.h> 77#include <sys/kauth.h> 78#include <sys/cprng.h> 79 80#ifdef PAX_ASLR_DEBUG 81#define PAX_DPRINTF(_fmt, args...) \ 82 do if (pax_aslr_debug) uprintf("%s: " _fmt "\n", __func__, ##args); \ 83 while (/*CONSTCOND*/0) 84#else 85#define PAX_DPRINTF(_fmt, args...) do {} while (/*CONSTCOND*/0) 86#endif 87 88#ifdef PAX_ASLR 89#include <sys/mman.h> 90 91int pax_aslr_enabled = 1; 92int pax_aslr_global = PAX_ASLR; 93 94#ifndef PAX_ASLR_DELTA_MMAP_LSB 95#define PAX_ASLR_DELTA_MMAP_LSB PGSHIFT 96#endif 97#ifndef PAX_ASLR_DELTA_MMAP_LEN 98#define PAX_ASLR_DELTA_MMAP_LEN ((sizeof(void *) * NBBY) / 2) 99#endif 100#ifndef PAX_ASLR_DELTA_MMAP_LEN32 101#define PAX_ASLR_DELTA_MMAP_LEN32 ((sizeof(uint32_t) * NBBY) / 2) 102#endif 103#ifndef PAX_ASLR_DELTA_STACK_LSB 104#define PAX_ASLR_DELTA_STACK_LSB PGSHIFT 105#endif 106#ifndef PAX_ASLR_DELTA_STACK_LEN 107#define PAX_ASLR_DELTA_STACK_LEN ((sizeof(void *) * NBBY) / 4) 108#endif 109#ifndef PAX_ASLR_DELTA_STACK_LEN32 110#define PAX_ASLR_DELTA_STACK_LEN32 ((sizeof(uint32_t) * NBBY) / 4) 111#endif 112#define PAX_ASLR_MAX_STACK_WASTE 8 113 114static bool pax_aslr_elf_flags_active(uint32_t); 115#endif /* PAX_ASLR */ 116 117#ifdef PAX_MPROTECT 118static int pax_mprotect_enabled = 1; 119static int pax_mprotect_global = PAX_MPROTECT; 120static bool pax_mprotect_elf_flags_active(uint32_t); 121#endif /* PAX_MPROTECT */ 122#ifdef PAX_MPROTECT_DEBUG 123int pax_mprotect_debug; 124#endif 125 126#ifdef PAX_SEGVGUARD 127#ifndef PAX_SEGVGUARD_EXPIRY 128#define PAX_SEGVGUARD_EXPIRY (2 * 60) 129#endif 130#ifndef PAX_SEGVGUARD_SUSPENSION 131#define PAX_SEGVGUARD_SUSPENSION (10 * 60) 132#endif 133#ifndef PAX_SEGVGUARD_MAXCRASHES 134#define PAX_SEGVGUARD_MAXCRASHES 5 135#endif 136 137#ifdef PAX_ASLR_DEBUG 138int pax_aslr_debug; 139/* flag set means disable */ 140int pax_aslr_flags; 141uint32_t pax_aslr_rand; 142#define PAX_ASLR_STACK 0x01 143#define PAX_ASLR_STACK_GAP 0x02 144#define PAX_ASLR_MMAP 0x04 145#define PAX_ASLR_EXEC_OFFSET 0x08 146#define PAX_ASLR_FIXED 0x10 147#endif 148 149static int pax_segvguard_enabled = 1; 150static int pax_segvguard_global = PAX_SEGVGUARD; 151static int pax_segvguard_expiry = PAX_SEGVGUARD_EXPIRY; 152static int pax_segvguard_suspension = PAX_SEGVGUARD_SUSPENSION; 153static int pax_segvguard_maxcrashes = PAX_SEGVGUARD_MAXCRASHES; 154 155static fileassoc_t segvguard_id; 156 157struct pax_segvguard_uid_entry { 158 uid_t sue_uid; 159 size_t sue_ncrashes; 160 time_t sue_expiry; 161 time_t sue_suspended; 162 LIST_ENTRY(pax_segvguard_uid_entry) sue_list; 163}; 164 165struct pax_segvguard_entry { 166 LIST_HEAD(, pax_segvguard_uid_entry) segv_uids; 167}; 168 169static bool pax_segvguard_elf_flags_active(uint32_t); 170static void pax_segvguard_cleanup_cb(void *); 171#endif /* PAX_SEGVGUARD */ 172 173SYSCTL_SETUP(sysctl_security_pax_setup, "sysctl security.pax setup") 174{ 175 const struct sysctlnode *rnode = NULL, *cnode; 176 177 sysctl_createv(clog, 0, NULL, &rnode, 178 CTLFLAG_PERMANENT, 179 CTLTYPE_NODE, "pax", 180 SYSCTL_DESCR("PaX (exploit mitigation) features."), 181 NULL, 0, NULL, 0, 182 CTL_SECURITY, CTL_CREATE, CTL_EOL); 183 184 cnode = rnode; 185 186#ifdef PAX_MPROTECT 187 rnode = cnode; 188 sysctl_createv(clog, 0, &rnode, &rnode, 189 CTLFLAG_PERMANENT, 190 CTLTYPE_NODE, "mprotect", 191 SYSCTL_DESCR("mprotect(2) W^X restrictions."), 192 NULL, 0, NULL, 0, 193 CTL_CREATE, CTL_EOL); 194 sysctl_createv(clog, 0, &rnode, NULL, 195 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 196 CTLTYPE_INT, "enabled", 197 SYSCTL_DESCR("Restrictions enabled."), 198 NULL, 0, &pax_mprotect_enabled, 0, 199 CTL_CREATE, CTL_EOL); 200 sysctl_createv(clog, 0, &rnode, NULL, 201 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 202 CTLTYPE_INT, "global", 203 SYSCTL_DESCR("When enabled, unless explicitly " 204 "specified, apply restrictions to " 205 "all processes."), 206 NULL, 0, &pax_mprotect_global, 0, 207 CTL_CREATE, CTL_EOL); 208#ifdef PAX_MPROTECT_DEBUG 209 sysctl_createv(clog, 0, &rnode, NULL, 210 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 211 CTLTYPE_INT, "debug", 212 SYSCTL_DESCR("print mprotect changes."), 213 NULL, 0, &pax_mprotect_debug, 0, 214 CTL_CREATE, CTL_EOL); 215#endif 216#endif /* PAX_MPROTECT */ 217 218#ifdef PAX_SEGVGUARD 219 rnode = cnode; 220 sysctl_createv(clog, 0, &rnode, &rnode, 221 CTLFLAG_PERMANENT, 222 CTLTYPE_NODE, "segvguard", 223 SYSCTL_DESCR("PaX segvguard."), 224 NULL, 0, NULL, 0, 225 CTL_CREATE, CTL_EOL); 226 sysctl_createv(clog, 0, &rnode, NULL, 227 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 228 CTLTYPE_INT, "enabled", 229 SYSCTL_DESCR("segvguard enabled."), 230 NULL, 0, &pax_segvguard_enabled, 0, 231 CTL_CREATE, CTL_EOL); 232 sysctl_createv(clog, 0, &rnode, NULL, 233 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 234 CTLTYPE_INT, "global", 235 SYSCTL_DESCR("segvguard all programs."), 236 NULL, 0, &pax_segvguard_global, 0, 237 CTL_CREATE, CTL_EOL); 238 sysctl_createv(clog, 0, &rnode, NULL, 239 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 240 CTLTYPE_INT, "expiry_timeout", 241 SYSCTL_DESCR("Entry expiry timeout (in seconds)."), 242 NULL, 0, &pax_segvguard_expiry, 0, 243 CTL_CREATE, CTL_EOL); 244 sysctl_createv(clog, 0, &rnode, NULL, 245 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 246 CTLTYPE_INT, "suspend_timeout", 247 SYSCTL_DESCR("Entry suspension timeout (in seconds)."), 248 NULL, 0, &pax_segvguard_suspension, 0, 249 CTL_CREATE, CTL_EOL); 250 sysctl_createv(clog, 0, &rnode, NULL, 251 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 252 CTLTYPE_INT, "max_crashes", 253 SYSCTL_DESCR("Max number of crashes before expiry."), 254 NULL, 0, &pax_segvguard_maxcrashes, 0, 255 CTL_CREATE, CTL_EOL); 256#endif /* PAX_SEGVGUARD */ 257 258#ifdef PAX_ASLR 259 rnode = cnode; 260 sysctl_createv(clog, 0, &rnode, &rnode, 261 CTLFLAG_PERMANENT, 262 CTLTYPE_NODE, "aslr", 263 SYSCTL_DESCR("Address Space Layout Randomization."), 264 NULL, 0, NULL, 0, 265 CTL_CREATE, CTL_EOL); 266 sysctl_createv(clog, 0, &rnode, NULL, 267 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 268 CTLTYPE_INT, "enabled", 269 SYSCTL_DESCR("Restrictions enabled."), 270 NULL, 0, &pax_aslr_enabled, 0, 271 CTL_CREATE, CTL_EOL); 272 sysctl_createv(clog, 0, &rnode, NULL, 273 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 274 CTLTYPE_INT, "global", 275 SYSCTL_DESCR("When enabled, unless explicitly " 276 "specified, apply to all processes."), 277 NULL, 0, &pax_aslr_global, 0, 278 CTL_CREATE, CTL_EOL); 279#ifdef PAX_ASLR_DEBUG 280 sysctl_createv(clog, 0, &rnode, NULL, 281 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 282 CTLTYPE_INT, "debug", 283 SYSCTL_DESCR("Pring ASLR selected addresses."), 284 NULL, 0, &pax_aslr_debug, 0, 285 CTL_CREATE, CTL_EOL); 286 sysctl_createv(clog, 0, &rnode, NULL, 287 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 288 CTLTYPE_INT, "flags", 289 SYSCTL_DESCR("Disable/Enable select ASLR features."), 290 NULL, 0, &pax_aslr_flags, 0, 291 CTL_CREATE, CTL_EOL); 292 sysctl_createv(clog, 0, &rnode, NULL, 293 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 294 CTLTYPE_INT, "rand", 295 SYSCTL_DESCR("Use the given fixed random value"), 296 NULL, 0, &pax_aslr_rand, 0, 297 CTL_CREATE, CTL_EOL); 298#endif 299 sysctl_createv(clog, 0, &rnode, NULL, 300 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE, 301 CTLTYPE_INT, "mmap_len", 302 SYSCTL_DESCR("Number of bits randomized for " 303 "mmap(2) calls."), 304 NULL, PAX_ASLR_DELTA_MMAP_LEN, NULL, 0, 305 CTL_CREATE, CTL_EOL); 306 sysctl_createv(clog, 0, &rnode, NULL, 307 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE, 308 CTLTYPE_INT, "stack_len", 309 SYSCTL_DESCR("Number of bits randomized for " 310 "the stack."), 311 NULL, PAX_ASLR_DELTA_STACK_LEN, NULL, 0, 312 CTL_CREATE, CTL_EOL); 313 sysctl_createv(clog, 0, &rnode, NULL, 314 CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE, 315 CTLTYPE_INT, "exec_len", 316 SYSCTL_DESCR("Number of bits randomized for " 317 "the PIE exec base."), 318 NULL, PAX_ASLR_DELTA_EXEC_LEN, NULL, 0, 319 CTL_CREATE, CTL_EOL); 320 321#endif /* PAX_ASLR */ 322} 323 324/* 325 * Initialize PaX. 326 */ 327void 328pax_init(void) 329{ 330#ifdef PAX_SEGVGUARD 331 int error; 332 333 error = fileassoc_register("segvguard", pax_segvguard_cleanup_cb, 334 &segvguard_id); 335 if (error) { 336 panic("pax_init: segvguard_id: error=%d\n", error); 337 } 338#endif /* PAX_SEGVGUARD */ 339#ifdef PAX_ASLR 340 /* Adjust maximum stack by the size we can consume for ASLR */ 341 extern rlim_t maxsmap; 342 maxsmap = MAXSSIZ - (MAXSSIZ / PAX_ASLR_MAX_STACK_WASTE); 343 // XXX: compat32 is not handled. 344#endif 345} 346 347void 348pax_setup_elf_flags(struct exec_package *epp, uint32_t elf_flags) 349{ 350 uint32_t flags = 0; 351 352#ifdef PAX_ASLR 353 if (pax_aslr_elf_flags_active(elf_flags)) { 354 flags |= P_PAX_ASLR; 355 } 356#endif 357#ifdef PAX_MPROTECT 358 if (pax_mprotect_elf_flags_active(elf_flags)) { 359 flags |= P_PAX_MPROTECT; 360 } 361#endif 362#ifdef PAX_SEGVGUARD 363 if (pax_segvguard_elf_flags_active(elf_flags)) { 364 flags |= P_PAX_GUARD; 365 } 366#endif 367 368 epp->ep_pax_flags = flags; 369} 370 371#if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD) || defined(PAX_ASLR) 372static inline bool 373pax_flags_active(uint32_t flags, uint32_t opt) 374{ 375 if (!(flags & opt)) 376 return false; 377 return true; 378} 379#endif /* PAX_MPROTECT || PAX_SEGVGUARD || PAX_ASLR */ 380 381#ifdef PAX_MPROTECT 382static bool 383pax_mprotect_elf_flags_active(uint32_t flags) 384{ 385 if (!pax_mprotect_enabled) 386 return false; 387 if (pax_mprotect_global && (flags & ELF_NOTE_PAX_NOMPROTECT) != 0) { 388 /* Mprotect explicitly disabled */ 389 return false; 390 } 391 if (!pax_mprotect_global && (flags & ELF_NOTE_PAX_MPROTECT) == 0) { 392 /* Mprotect not requested */ 393 return false; 394 } 395 return true; 396} 397 398void 399pax_mprotect_adjust( 400#ifdef PAX_MPROTECT_DEBUG 401 const char *file, size_t line, 402#endif 403 struct lwp *l, vm_prot_t *prot, vm_prot_t *maxprot) 404{ 405 uint32_t flags; 406 407 flags = l->l_proc->p_pax; 408 if (!pax_flags_active(flags, P_PAX_MPROTECT)) 409 return; 410 411 if ((*prot & (VM_PROT_WRITE|VM_PROT_EXECUTE)) != VM_PROT_EXECUTE) { 412#ifdef PAX_MPROTECT_DEBUG 413 struct proc *p = l->l_proc; 414 if ((*prot & VM_PROT_EXECUTE) && pax_mprotect_debug) { 415 printf("%s: %s,%zu: %d.%d (%s): -x\n", 416 __func__, file, line, 417 p->p_pid, l->l_lid, p->p_comm); 418 } 419#endif 420 *prot &= ~VM_PROT_EXECUTE; 421 *maxprot &= ~VM_PROT_EXECUTE; 422 } else { 423#ifdef PAX_MPROTECT_DEBUG 424 struct proc *p = l->l_proc; 425 if ((*prot & VM_PROT_WRITE) && pax_mprotect_debug) { 426 printf("%s: %s,%zu: %d.%d (%s): -w\n", 427 __func__, file, line, 428 p->p_pid, l->l_lid, p->p_comm); 429 } 430#endif 431 *prot &= ~VM_PROT_WRITE; 432 *maxprot &= ~VM_PROT_WRITE; 433 } 434} 435#endif /* PAX_MPROTECT */ 436 437#ifdef PAX_ASLR 438static bool 439pax_aslr_elf_flags_active(uint32_t flags) 440{ 441 if (!pax_aslr_enabled) 442 return false; 443 if (pax_aslr_global && (flags & ELF_NOTE_PAX_NOASLR) != 0) { 444 /* ASLR explicitly disabled */ 445 return false; 446 } 447 if (!pax_aslr_global && (flags & ELF_NOTE_PAX_ASLR) == 0) { 448 /* ASLR not requested */ 449 return false; 450 } 451 return true; 452} 453 454bool 455pax_aslr_epp_active(struct exec_package *epp) 456{ 457 return pax_flags_active(epp->ep_pax_flags, P_PAX_ASLR); 458} 459 460bool 461pax_aslr_active(struct lwp *l) 462{ 463 return pax_flags_active(l->l_proc->p_pax, P_PAX_ASLR); 464} 465 466void 467pax_aslr_init_vm(struct lwp *l, struct vmspace *vm, struct exec_package *ep) 468{ 469 if (!pax_aslr_active(l)) 470 return; 471 472#ifdef PAX_ASLR_DEBUG 473 if (pax_aslr_flags & PAX_ASLR_MMAP) 474 return; 475#endif 476 477 uint32_t len = (ep->ep_flags & EXEC_32) ? 478 PAX_ASLR_DELTA_MMAP_LEN32 : PAX_ASLR_DELTA_MMAP_LEN; 479 480 uint32_t rand = cprng_fast32(); 481#ifdef PAX_ASLR_DEBUG 482 if (pax_aslr_flags & PAX_ASLR_FIXED) 483 rand = pax_aslr_rand; 484#endif 485 vm->vm_aslr_delta_mmap = PAX_ASLR_DELTA(rand, 486 PAX_ASLR_DELTA_MMAP_LSB, len); 487 488 PAX_DPRINTF("delta_mmap=%#jx/%u", 489 (uintmax_t)vm->vm_aslr_delta_mmap, len); 490} 491 492void 493pax_aslr_mmap(struct lwp *l, vaddr_t *addr, vaddr_t orig_addr, int f) 494{ 495 if (!pax_aslr_active(l)) 496 return; 497#ifdef PAX_ASLR_DEBUG 498 char buf[256]; 499 500 if (pax_aslr_flags & PAX_ASLR_MMAP) 501 return; 502 503 if (pax_aslr_debug) 504 snprintb(buf, sizeof(buf), MAP_FMT, f); 505 else 506 buf[0] = '\0'; 507#endif 508 509 if (!(f & MAP_FIXED) && ((orig_addr == 0) || !(f & MAP_ANON))) { 510 PAX_DPRINTF("applying to %#jx orig_addr=%#jx f=%s", 511 (uintmax_t)*addr, (uintmax_t)orig_addr, buf); 512 if (!(l->l_proc->p_vmspace->vm_map.flags & VM_MAP_TOPDOWN)) 513 *addr += l->l_proc->p_vmspace->vm_aslr_delta_mmap; 514 else 515 *addr -= l->l_proc->p_vmspace->vm_aslr_delta_mmap; 516 PAX_DPRINTF("result %#jx", (uintmax_t)*addr); 517 } else { 518 PAX_DPRINTF("not applying to %#jx orig_addr=%#jx f=%s", 519 (uintmax_t)*addr, (uintmax_t)orig_addr, buf); 520 } 521} 522 523#define PAX_TRUNC(a, b) ((a) & ~((b) - 1)) 524vaddr_t 525pax_aslr_exec_offset(struct exec_package *epp, vaddr_t align) 526{ 527 size_t pax_align, l2, delta; 528 uint32_t rand; 529 vaddr_t offset; 530 531 if (!pax_aslr_epp_active(epp)) 532 goto out; 533 534#ifdef PAX_ASLR_DEBUG 535 if (pax_aslr_flags & PAX_ASLR_EXEC_OFFSET) 536 goto out; 537#endif 538 539 pax_align = align == 0 ? PGSHIFT : align; 540 l2 = ilog2(pax_align); 541 542 rand = cprng_fast32(); 543#ifdef PAX_ASLR_DEBUG 544 if (pax_aslr_flags & PAX_ASLR_FIXED) 545 rand = pax_aslr_rand; 546#endif 547 delta = PAX_ASLR_DELTA(rand, l2, PAX_ASLR_DELTA_EXEC_LEN); 548 offset = PAX_TRUNC(delta, pax_align) + PAGE_SIZE; 549 550 PAX_DPRINTF("rand=%#x l2=%#zx pax_align=%#zx delta=%#zx offset=%#jx", 551 rand, l2, pax_align, delta, (uintmax_t)offset); 552 return offset; 553out: 554 return MAX(align, PAGE_SIZE); 555} 556 557void 558pax_aslr_stack(struct exec_package *epp, u_long *max_stack_size) 559{ 560 if (!pax_aslr_epp_active(epp)) 561 return; 562#ifdef PAX_ASLR_DEBUG 563 if (pax_aslr_flags & PAX_ASLR_STACK) 564 return; 565#endif 566 567 uint32_t len = (epp->ep_flags & EXEC_32) ? 568 PAX_ASLR_DELTA_STACK_LEN32 : PAX_ASLR_DELTA_STACK_LEN; 569 uint32_t rand = cprng_fast32(); 570#ifdef PAX_ASLR_DEBUG 571 if (pax_aslr_flags & PAX_ASLR_FIXED) 572 rand = pax_aslr_rand; 573#endif 574 u_long d = PAX_ASLR_DELTA(rand, PAX_ASLR_DELTA_STACK_LSB, len); 575 d &= (*max_stack_size / PAX_ASLR_MAX_STACK_WASTE) - 1; 576 u_long newminsaddr = (u_long)STACK_GROW(epp->ep_minsaddr, d); 577 PAX_DPRINTF("old minsaddr=%#jx delta=%#lx new minsaddr=%#lx", 578 (uintmax_t)epp->ep_minsaddr, d, newminsaddr); 579 epp->ep_minsaddr = (vaddr_t)newminsaddr; 580 *max_stack_size -= d; 581} 582 583uint32_t 584pax_aslr_stack_gap(struct exec_package *epp) 585{ 586 if (!pax_aslr_epp_active(epp)) 587 return 0; 588 589#ifdef PAX_ASLR_DEBUG 590 if (pax_aslr_flags & PAX_ASLR_STACK_GAP) 591 return 0; 592#endif 593 594 uint32_t rand = cprng_fast32(); 595#ifdef PAX_ASLR_DEBUG 596 if (pax_aslr_flags & PAX_ASLR_FIXED) 597 rand = pax_aslr_rand; 598#endif 599 rand %= PAGE_SIZE; 600 PAX_DPRINTF("stack gap=%#x\n", rand); 601 return rand; 602} 603#endif /* PAX_ASLR */ 604 605#ifdef PAX_SEGVGUARD 606static bool 607pax_segvguard_elf_flags_active(uint32_t flags) 608{ 609 if (!pax_segvguard_enabled) 610 return false; 611 if (pax_segvguard_global && (flags & ELF_NOTE_PAX_NOGUARD) != 0) { 612 /* Segvguard explicitly disabled */ 613 return false; 614 } 615 if (!pax_segvguard_global && (flags & ELF_NOTE_PAX_GUARD) == 0) { 616 /* Segvguard not requested */ 617 return false; 618 } 619 return true; 620} 621 622static void 623pax_segvguard_cleanup_cb(void *v) 624{ 625 struct pax_segvguard_entry *p = v; 626 struct pax_segvguard_uid_entry *up; 627 628 if (p == NULL) { 629 return; 630 } 631 while ((up = LIST_FIRST(&p->segv_uids)) != NULL) { 632 LIST_REMOVE(up, sue_list); 633 kmem_free(up, sizeof(*up)); 634 } 635 kmem_free(p, sizeof(*p)); 636} 637 638/* 639 * Called when a process of image vp generated a segfault. 640 */ 641int 642pax_segvguard(struct lwp *l, struct vnode *vp, const char *name, 643 bool crashed) 644{ 645 struct pax_segvguard_entry *p; 646 struct pax_segvguard_uid_entry *up; 647 struct timeval tv; 648 uid_t uid; 649 uint32_t flags; 650 bool have_uid; 651 652 flags = l->l_proc->p_pax; 653 if (!pax_flags_active(flags, P_PAX_GUARD)) 654 return 0; 655 656 if (vp == NULL) 657 return EFAULT; 658 659 /* Check if we already monitor the file. */ 660 p = fileassoc_lookup(vp, segvguard_id); 661 662 /* Fast-path if starting a program we don't know. */ 663 if (p == NULL && !crashed) 664 return 0; 665 666 microtime(&tv); 667 668 /* 669 * If a program we don't know crashed, we need to create a new entry 670 * for it. 671 */ 672 if (p == NULL) { 673 p = kmem_alloc(sizeof(*p), KM_SLEEP); 674 fileassoc_add(vp, segvguard_id, p); 675 LIST_INIT(&p->segv_uids); 676 677 /* 678 * Initialize a new entry with "crashes so far" of 1. 679 * The expiry time is when we purge the entry if it didn't 680 * reach the limit. 681 */ 682 up = kmem_alloc(sizeof(*up), KM_SLEEP); 683 up->sue_uid = kauth_cred_getuid(l->l_cred); 684 up->sue_ncrashes = 1; 685 up->sue_expiry = tv.tv_sec + pax_segvguard_expiry; 686 up->sue_suspended = 0; 687 LIST_INSERT_HEAD(&p->segv_uids, up, sue_list); 688 return 0; 689 } 690 691 /* 692 * A program we "know" either executed or crashed again. 693 * See if it's a culprit we're familiar with. 694 */ 695 uid = kauth_cred_getuid(l->l_cred); 696 have_uid = false; 697 LIST_FOREACH(up, &p->segv_uids, sue_list) { 698 if (up->sue_uid == uid) { 699 have_uid = true; 700 break; 701 } 702 } 703 704 /* 705 * It's someone else. Add an entry for him if we crashed. 706 */ 707 if (!have_uid) { 708 if (crashed) { 709 up = kmem_alloc(sizeof(*up), KM_SLEEP); 710 up->sue_uid = uid; 711 up->sue_ncrashes = 1; 712 up->sue_expiry = tv.tv_sec + pax_segvguard_expiry; 713 up->sue_suspended = 0; 714 LIST_INSERT_HEAD(&p->segv_uids, up, sue_list); 715 } 716 return 0; 717 } 718 719 if (crashed) { 720 /* Check if timer on previous crashes expired first. */ 721 if (up->sue_expiry < tv.tv_sec) { 722 log(LOG_INFO, "PaX Segvguard: [%s] Suspension" 723 " expired.\n", name ? name : "unknown"); 724 up->sue_ncrashes = 1; 725 up->sue_expiry = tv.tv_sec + pax_segvguard_expiry; 726 up->sue_suspended = 0; 727 return 0; 728 } 729 730 up->sue_ncrashes++; 731 732 if (up->sue_ncrashes >= pax_segvguard_maxcrashes) { 733 log(LOG_ALERT, "PaX Segvguard: [%s] Suspending " 734 "execution for %d seconds after %zu crashes.\n", 735 name ? name : "unknown", pax_segvguard_suspension, 736 up->sue_ncrashes); 737 738 /* Suspend this program for a while. */ 739 up->sue_suspended = tv.tv_sec + pax_segvguard_suspension; 740 up->sue_ncrashes = 0; 741 up->sue_expiry = 0; 742 } 743 } else { 744 /* Are we supposed to be suspended? */ 745 if (up->sue_suspended > tv.tv_sec) { 746 log(LOG_ALERT, "PaX Segvguard: [%s] Preventing " 747 "execution due to repeated segfaults.\n", name ? 748 name : "unknown"); 749 return EPERM; 750 } 751 } 752 753 return 0; 754} 755#endif /* PAX_SEGVGUARD */ 756