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