1 /* $NetBSD: kern_pax.c,v 1.65 2026/01/04 01:36:27 riastradh Exp $ */ 2 3 /* 4 * Copyright (c) 2015, 2020 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 (at) 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.65 2026/01/04 01:36:27 riastradh Exp $"); 61 62 #include "opt_pax.h" 63 64 #include <sys/param.h> 65 #include <sys/types.h> 66 67 #include <sys/bitops.h> 68 #include <sys/cprng.h> 69 #include <sys/exec.h> 70 #include <sys/exec_elf.h> 71 #include <sys/kauth.h> 72 #include <sys/kmem.h> 73 #include <sys/mman.h> 74 #include <sys/pax.h> 75 #include <sys/proc.h> 76 #include <sys/queue.h> 77 #include <sys/sdt.h> 78 #include <sys/sysctl.h> 79 #include <sys/syslog.h> 80 #include <sys/vnode.h> 81 82 #ifdef PAX_ASLR_DEBUG 83 #define PAX_DPRINTF(_fmt, args...) \ 84 do if (pax_aslr_debug) uprintf("%s: " _fmt "\n", __func__, ##args); \ 85 while (/*CONSTCOND*/0) 86 #else 87 #define PAX_DPRINTF(_fmt, args...) do {} while (/*CONSTCOND*/0) 88 #endif 89 90 #ifdef PAX_ASLR 91 #include <sys/mman.h> 92 #include <sys/resourcevar.h> 93 94 int pax_aslr_enabled = 1; 95 int pax_aslr_global = PAX_ASLR; 96 97 #ifndef PAX_ASLR_DELTA_MMAP_LSB 98 #define PAX_ASLR_DELTA_MMAP_LSB PGSHIFT 99 #endif 100 #ifndef PAX_ASLR_DELTA_MMAP_LEN 101 #define PAX_ASLR_DELTA_MMAP_LEN ((sizeof(void *) * NBBY) / 2) 102 #endif 103 #ifndef PAX_ASLR_DELTA_MMAP_LEN32 104 #define PAX_ASLR_DELTA_MMAP_LEN32 ((sizeof(uint32_t) * NBBY) / 2) 105 #endif 106 #ifndef PAX_ASLR_DELTA_STACK_LSB 107 #define PAX_ASLR_DELTA_STACK_LSB PGSHIFT 108 #endif 109 #ifndef PAX_ASLR_DELTA_STACK_LEN 110 #define PAX_ASLR_DELTA_STACK_LEN ((sizeof(void *) * NBBY) / 4) 111 #endif 112 #ifndef PAX_ASLR_DELTA_STACK_LEN32 113 #define PAX_ASLR_DELTA_STACK_LEN32 ((sizeof(uint32_t) * NBBY) / 4) 114 #endif 115 #define PAX_ASLR_MAX_STACK_WASTE 8 116 117 #ifdef PAX_ASLR_DEBUG 118 int pax_aslr_debug; 119 /* flag set means disable */ 120 int pax_aslr_flags; 121 uint32_t pax_aslr_rand; 122 #define PAX_ASLR_STACK 0x01 123 #define PAX_ASLR_STACK_GAP 0x02 124 #define PAX_ASLR_MMAP 0x04 125 #define PAX_ASLR_EXEC_OFFSET 0x08 126 #define PAX_ASLR_RTLD_OFFSET 0x10 127 #define PAX_ASLR_FIXED 0x20 128 #endif 129 130 static bool pax_aslr_elf_flags_active(uint32_t); 131 #endif /* PAX_ASLR */ 132 133 #ifdef PAX_MPROTECT 134 static int pax_mprotect_enabled = 1; 135 static int pax_mprotect_global = PAX_MPROTECT; 136 static int pax_mprotect_ptrace = 1; 137 static bool pax_mprotect_elf_flags_active(uint32_t); 138 #endif /* PAX_MPROTECT */ 139 #ifdef PAX_MPROTECT_DEBUG 140 int pax_mprotect_debug; 141 #endif 142 143 #ifdef PAX_SEGVGUARD 144 #ifndef PAX_SEGVGUARD_EXPIRY 145 #define PAX_SEGVGUARD_EXPIRY (2 * 60) 146 #endif 147 #ifndef PAX_SEGVGUARD_SUSPENSION 148 #define PAX_SEGVGUARD_SUSPENSION (10 * 60) 149 #endif 150 #ifndef PAX_SEGVGUARD_MAXCRASHES 151 #define PAX_SEGVGUARD_MAXCRASHES 5 152 #endif 153 154 155 static int pax_segvguard_enabled = 1; 156 static int pax_segvguard_global = PAX_SEGVGUARD; 157 static int pax_segvguard_expiry = PAX_SEGVGUARD_EXPIRY; 158 static int pax_segvguard_suspension = PAX_SEGVGUARD_SUSPENSION; 159 static int pax_segvguard_maxcrashes = PAX_SEGVGUARD_MAXCRASHES; 160 161 struct pax_segvguard_uid_entry { 162 uid_t sue_uid; 163 size_t sue_ncrashes; 164 time_t sue_expiry; 165 time_t sue_suspended; 166 LIST_ENTRY(pax_segvguard_uid_entry) sue_list; 167 }; 168 169 struct pax_segvguard_entry { 170 LIST_HEAD(, pax_segvguard_uid_entry) segv_uids; 171 }; 172 173 static bool pax_segvguard_elf_flags_active(uint32_t); 174 #endif /* PAX_SEGVGUARD */ 175 176 SYSCTL_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("Print 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 */ 338 void 339 pax_init(void) 340 { 341 #ifdef PAX_ASLR 342 /* Adjust maximum stack by the size we can consume for ASLR */ 343 maxsmap = MAXSSIZ - (MAXSSIZ / PAX_ASLR_MAX_STACK_WASTE); 344 // XXX: compat32 is not handled. 345 #endif 346 } 347 348 void 349 pax_set_flags(struct exec_package *epp, struct proc *p) 350 { 351 p->p_pax = epp->ep_pax_flags; 352 353 #ifdef PAX_MPROTECT 354 if (pax_mprotect_ptrace == 0) 355 return; 356 /* 357 * If we are running under the debugger, turn off MPROTECT so 358 * the debugger can insert/delete breakpoints 359 */ 360 if (p->p_slflag & PSL_TRACED) 361 p->p_pax &= ~P_PAX_MPROTECT; 362 #endif 363 } 364 365 void 366 pax_setup_elf_flags(struct exec_package *epp, uint32_t elf_flags) 367 { 368 uint32_t flags = 0; 369 370 #ifdef PAX_ASLR 371 if (pax_aslr_elf_flags_active(elf_flags)) { 372 flags |= P_PAX_ASLR; 373 } 374 #endif 375 #ifdef PAX_MPROTECT 376 if (pax_mprotect_elf_flags_active(elf_flags)) { 377 flags |= P_PAX_MPROTECT; 378 } 379 #endif 380 #ifdef PAX_SEGVGUARD 381 if (pax_segvguard_elf_flags_active(elf_flags)) { 382 flags |= P_PAX_GUARD; 383 } 384 #endif 385 386 epp->ep_pax_flags = flags; 387 } 388 389 #if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD) || defined(PAX_ASLR) 390 static inline bool 391 pax_flags_active(uint32_t flags, uint32_t opt) 392 { 393 if (!(flags & opt)) 394 return false; 395 return true; 396 } 397 #endif /* PAX_MPROTECT || PAX_SEGVGUARD || PAX_ASLR */ 398 399 #ifdef PAX_MPROTECT 400 static bool 401 pax_mprotect_elf_flags_active(uint32_t flags) 402 { 403 if (!pax_mprotect_enabled) 404 return false; 405 if (pax_mprotect_global && (flags & ELF_NOTE_PAX_NOMPROTECT) != 0) { 406 /* Mprotect explicitly disabled */ 407 return false; 408 } 409 if (!pax_mprotect_global && (flags & ELF_NOTE_PAX_MPROTECT) == 0) { 410 /* Mprotect not requested */ 411 return false; 412 } 413 return true; 414 } 415 416 vm_prot_t 417 pax_mprotect_maxprotect( 418 #ifdef PAX_MPROTECT_DEBUG 419 const char *file, size_t line, 420 #endif 421 struct lwp *l, vm_prot_t active, vm_prot_t extra, vm_prot_t maxprot) 422 { 423 uint32_t flags; 424 425 flags = l->l_proc->p_pax; 426 if (!pax_flags_active(flags, P_PAX_MPROTECT)) 427 return maxprot; 428 429 return (active|extra) & maxprot; 430 } 431 432 int 433 pax_mprotect_validate( 434 #ifdef PAX_MPROTECT_DEBUG 435 const char *file, size_t line, 436 #endif 437 struct lwp *l, vm_prot_t prot) 438 { 439 uint32_t flags; 440 441 flags = l->l_proc->p_pax; 442 if (!pax_flags_active(flags, P_PAX_MPROTECT)) 443 return 0; 444 445 if ((prot & (VM_PROT_WRITE|VM_PROT_EXECUTE)) == 446 (VM_PROT_WRITE|VM_PROT_EXECUTE)) { 447 #ifdef PAX_MPROTECT_DEBUG 448 struct proc *p = l->l_proc; 449 450 if (pax_mprotect_debug) 451 printf("%s: %s,%zu: %d.%d (%s): WX rejected\n", 452 __func__, file, line, 453 p->p_pid, l->l_lid, p->p_comm); 454 #endif 455 return SET_ERROR(EACCES); 456 } 457 return 0; 458 } 459 460 /* 461 * Bypass MPROTECT for traced processes 462 */ 463 int 464 pax_mprotect_prot(struct lwp *l) 465 { 466 uint32_t flags; 467 468 flags = l->l_proc->p_pax; 469 if (!pax_flags_active(flags, P_PAX_MPROTECT)) 470 return 0; 471 if (pax_mprotect_ptrace < 2) 472 return 0; 473 return UVM_EXTRACT_PROT_ALL; 474 } 475 476 477 #endif /* PAX_MPROTECT */ 478 479 #ifdef PAX_ASLR 480 static bool 481 pax_aslr_elf_flags_active(uint32_t flags) 482 { 483 if (!pax_aslr_enabled) 484 return false; 485 if (pax_aslr_global && (flags & ELF_NOTE_PAX_NOASLR) != 0) { 486 /* ASLR explicitly disabled */ 487 return false; 488 } 489 if (!pax_aslr_global && (flags & ELF_NOTE_PAX_ASLR) == 0) { 490 /* ASLR not requested */ 491 return false; 492 } 493 return true; 494 } 495 496 static bool 497 pax_aslr_epp_active(struct exec_package *epp) 498 { 499 if (__predict_false((epp->ep_flags & (EXEC_32|EXEC_TOPDOWN_VM)) == 0)) 500 return false; 501 return pax_flags_active(epp->ep_pax_flags, P_PAX_ASLR); 502 } 503 504 static bool 505 pax_aslr_active(struct lwp *l) 506 { 507 return pax_flags_active(l->l_proc->p_pax, P_PAX_ASLR); 508 } 509 510 void 511 pax_aslr_init_vm(struct lwp *l, struct vmspace *vm, struct exec_package *ep) 512 { 513 if (!pax_aslr_active(l)) 514 return; 515 516 if (__predict_false((ep->ep_flags & (EXEC_32|EXEC_TOPDOWN_VM)) == 0)) 517 return; 518 519 #ifdef PAX_ASLR_DEBUG 520 if (pax_aslr_flags & PAX_ASLR_MMAP) 521 return; 522 #endif 523 524 uint32_t len = (ep->ep_flags & EXEC_32) ? 525 PAX_ASLR_DELTA_MMAP_LEN32 : PAX_ASLR_DELTA_MMAP_LEN; 526 527 uint32_t rand = cprng_fast32(); 528 #ifdef PAX_ASLR_DEBUG 529 if (pax_aslr_flags & PAX_ASLR_FIXED) 530 rand = pax_aslr_rand; 531 #endif 532 vm->vm_aslr_delta_mmap = PAX_ASLR_DELTA(rand, 533 PAX_ASLR_DELTA_MMAP_LSB, len); 534 535 PAX_DPRINTF("delta_mmap=%#jx/%u", 536 (uintmax_t)vm->vm_aslr_delta_mmap, len); 537 } 538 539 void 540 pax_aslr_mmap(struct lwp *l, vaddr_t *addr, vaddr_t orig_addr, int f) 541 { 542 if (!pax_aslr_active(l)) 543 return; 544 #ifdef PAX_ASLR_DEBUG 545 char buf[256]; 546 547 if (pax_aslr_flags & PAX_ASLR_MMAP) 548 return; 549 550 if (pax_aslr_debug) 551 snprintb(buf, sizeof(buf), MAP_FMT, f); 552 else 553 buf[0] = '\0'; 554 #endif 555 556 if (!(f & MAP_FIXED) && ((orig_addr == 0) || !(f & MAP_ANON))) { 557 PAX_DPRINTF("applying to %#jx orig_addr=%#jx f=%s", 558 (uintmax_t)*addr, (uintmax_t)orig_addr, buf); 559 if (!(l->l_proc->p_vmspace->vm_map.flags & VM_MAP_TOPDOWN)) 560 *addr += l->l_proc->p_vmspace->vm_aslr_delta_mmap; 561 else 562 *addr -= l->l_proc->p_vmspace->vm_aslr_delta_mmap; 563 PAX_DPRINTF("result %#jx", (uintmax_t)*addr); 564 } else { 565 PAX_DPRINTF("not applying to %#jx orig_addr=%#jx f=%s", 566 (uintmax_t)*addr, (uintmax_t)orig_addr, buf); 567 } 568 } 569 570 static vaddr_t 571 pax_aslr_offset(vaddr_t align) 572 { 573 size_t pax_align, l2, delta; 574 uint32_t rand; 575 vaddr_t offset; 576 577 pax_align = align == 0 ? PAGE_SIZE : align; 578 l2 = ilog2(pax_align); 579 580 rand = cprng_fast32(); 581 #ifdef PAX_ASLR_DEBUG 582 if (pax_aslr_flags & PAX_ASLR_FIXED) 583 rand = pax_aslr_rand; 584 #endif 585 586 #define PAX_TRUNC(a, b) ((a) & ~((b) - 1)) 587 588 delta = PAX_ASLR_DELTA(rand, l2, PAX_ASLR_DELTA_EXEC_LEN); 589 offset = PAX_TRUNC(delta, pax_align); 590 offset = MAX(offset, pax_align); 591 592 PAX_DPRINTF("rand=%#x l2=%#zx pax_align=%#zx delta=%#zx offset=%#jx", 593 rand, l2, pax_align, delta, (uintmax_t)offset); 594 595 return offset; 596 } 597 598 vaddr_t 599 pax_aslr_exec_offset(struct exec_package *epp, vaddr_t align) 600 { 601 if (!pax_aslr_epp_active(epp)) 602 goto out; 603 604 #ifdef PAX_ASLR_DEBUG 605 if (pax_aslr_flags & PAX_ASLR_EXEC_OFFSET) 606 goto out; 607 #endif 608 return pax_aslr_offset(align); 609 out: 610 return MAX(align, PAGE_SIZE); 611 } 612 613 voff_t 614 pax_aslr_rtld_offset(struct exec_package *epp, vaddr_t align, int use_topdown) 615 { 616 voff_t offset; 617 618 if (!pax_aslr_epp_active(epp)) 619 return 0; 620 621 #ifdef PAX_ASLR_DEBUG 622 if (pax_aslr_flags & PAX_ASLR_RTLD_OFFSET) 623 return 0; 624 #endif 625 offset = pax_aslr_offset(align); 626 if (use_topdown) 627 offset = -offset; 628 629 return offset; 630 } 631 632 void 633 pax_aslr_stack(struct exec_package *epp, vsize_t *max_stack_size) 634 { 635 if (!pax_aslr_epp_active(epp)) 636 return; 637 #ifdef PAX_ASLR_DEBUG 638 if (pax_aslr_flags & PAX_ASLR_STACK) 639 return; 640 #endif 641 642 uint32_t len = (epp->ep_flags & EXEC_32) ? 643 PAX_ASLR_DELTA_STACK_LEN32 : PAX_ASLR_DELTA_STACK_LEN; 644 uint32_t rand = cprng_fast32(); 645 #ifdef PAX_ASLR_DEBUG 646 if (pax_aslr_flags & PAX_ASLR_FIXED) 647 rand = pax_aslr_rand; 648 #endif 649 u_long d = PAX_ASLR_DELTA(rand, PAX_ASLR_DELTA_STACK_LSB, len); 650 d &= (*max_stack_size / PAX_ASLR_MAX_STACK_WASTE) - 1; 651 u_long newminsaddr = (u_long)STACK_GROW(epp->ep_minsaddr, d); 652 PAX_DPRINTF("old minsaddr=%#jx delta=%#lx new minsaddr=%#lx", 653 (uintmax_t)epp->ep_minsaddr, d, newminsaddr); 654 epp->ep_minsaddr = (vaddr_t)newminsaddr; 655 *max_stack_size -= d; 656 } 657 658 uint32_t 659 pax_aslr_stack_gap(struct exec_package *epp) 660 { 661 if (!pax_aslr_epp_active(epp)) 662 return 0; 663 664 #ifdef PAX_ASLR_DEBUG 665 if (pax_aslr_flags & PAX_ASLR_STACK_GAP) 666 return 0; 667 #endif 668 669 uint32_t rand = cprng_fast32(); 670 #ifdef PAX_ASLR_DEBUG 671 if (pax_aslr_flags & PAX_ASLR_FIXED) 672 rand = pax_aslr_rand; 673 #endif 674 rand %= PAGE_SIZE; 675 PAX_DPRINTF("stack gap=%#x\n", rand); 676 return rand; 677 } 678 #endif /* PAX_ASLR */ 679 680 #ifdef PAX_SEGVGUARD 681 static bool 682 pax_segvguard_elf_flags_active(uint32_t flags) 683 { 684 if (!pax_segvguard_enabled) 685 return false; 686 if (pax_segvguard_global && (flags & ELF_NOTE_PAX_NOGUARD) != 0) { 687 /* Segvguard explicitly disabled */ 688 return false; 689 } 690 if (!pax_segvguard_global && (flags & ELF_NOTE_PAX_GUARD) == 0) { 691 /* Segvguard not requested */ 692 return false; 693 } 694 return true; 695 } 696 697 void 698 pax_segvguard_cleanup(struct vnode *vp) 699 { 700 struct pax_segvguard_entry *p = vp->v_segvguard; 701 struct pax_segvguard_uid_entry *up; 702 703 if (__predict_true(p == NULL)) { 704 return; 705 } 706 while ((up = LIST_FIRST(&p->segv_uids)) != NULL) { 707 LIST_REMOVE(up, sue_list); 708 kmem_free(up, sizeof(*up)); 709 } 710 kmem_free(p, sizeof(*p)); 711 vp->v_segvguard = NULL; 712 } 713 714 /* 715 * Called when a process of image vp generated a segfault. 716 * 717 * => exec_lock must be held by the caller 718 * => if "crashed" is true, exec_lock must be held for write 719 */ 720 int 721 pax_segvguard(struct lwp *l, struct vnode *vp, const char *name, bool crashed) 722 { 723 struct pax_segvguard_entry *p; 724 struct pax_segvguard_uid_entry *up; 725 struct timeval tv; 726 uid_t uid; 727 uint32_t flags; 728 bool have_uid; 729 730 KASSERT(rw_lock_held(&exec_lock)); 731 KASSERT(!crashed || rw_write_held(&exec_lock)); 732 733 flags = l->l_proc->p_pax; 734 if (!pax_flags_active(flags, P_PAX_GUARD)) 735 return 0; 736 737 if (vp == NULL) 738 return SET_ERROR(EFAULT); 739 740 /* Fast-path if starting a program we don't know. */ 741 if ((p = vp->v_segvguard) == NULL && !crashed) 742 return 0; 743 744 microtime(&tv); 745 746 /* 747 * If a program we don't know crashed, we need to create a new entry 748 * for it. 749 */ 750 if (p == NULL) { 751 p = kmem_alloc(sizeof(*p), KM_SLEEP); 752 vp->v_segvguard = p; 753 LIST_INIT(&p->segv_uids); 754 755 /* 756 * Initialize a new entry with "crashes so far" of 1. 757 * The expiry time is when we purge the entry if it didn't 758 * reach the limit. 759 */ 760 up = kmem_alloc(sizeof(*up), KM_SLEEP); 761 up->sue_uid = kauth_cred_getuid(l->l_cred); 762 up->sue_ncrashes = 1; 763 up->sue_expiry = tv.tv_sec + pax_segvguard_expiry; 764 up->sue_suspended = 0; 765 LIST_INSERT_HEAD(&p->segv_uids, up, sue_list); 766 return 0; 767 } 768 769 /* 770 * A program we "know" either executed or crashed again. 771 * See if it's a culprit we're familiar with. 772 */ 773 uid = kauth_cred_getuid(l->l_cred); 774 have_uid = false; 775 LIST_FOREACH(up, &p->segv_uids, sue_list) { 776 if (up->sue_uid == uid) { 777 have_uid = true; 778 break; 779 } 780 } 781 782 /* 783 * It's someone else. Add an entry for him if we crashed. 784 */ 785 if (!have_uid) { 786 if (crashed) { 787 up = kmem_alloc(sizeof(*up), KM_SLEEP); 788 up->sue_uid = uid; 789 up->sue_ncrashes = 1; 790 up->sue_expiry = tv.tv_sec + pax_segvguard_expiry; 791 up->sue_suspended = 0; 792 LIST_INSERT_HEAD(&p->segv_uids, up, sue_list); 793 } 794 return 0; 795 } 796 797 if (crashed) { 798 /* Check if timer on previous crashes expired first. */ 799 if (up->sue_expiry < tv.tv_sec) { 800 log(LOG_INFO, "PaX Segvguard: [%s] Suspension" 801 " expired.\n", name ? name : "unknown"); 802 up->sue_ncrashes = 1; 803 up->sue_expiry = tv.tv_sec + pax_segvguard_expiry; 804 up->sue_suspended = 0; 805 return 0; 806 } 807 808 up->sue_ncrashes++; 809 810 if (up->sue_ncrashes >= pax_segvguard_maxcrashes) { 811 log(LOG_ALERT, "PaX Segvguard: [%s] Suspending " 812 "execution for %d seconds after %zu crashes.\n", 813 name ? name : "unknown", pax_segvguard_suspension, 814 up->sue_ncrashes); 815 816 /* Suspend this program for a while. */ 817 up->sue_suspended = tv.tv_sec + pax_segvguard_suspension; 818 up->sue_ncrashes = 0; 819 up->sue_expiry = 0; 820 } 821 } else { 822 /* Are we supposed to be suspended? */ 823 if (up->sue_suspended > tv.tv_sec) { 824 log(LOG_ALERT, "PaX Segvguard: [%s] Preventing " 825 "execution due to repeated segfaults.\n", name ? 826 name : "unknown"); 827 return SET_ERROR(EPERM); 828 } 829 } 830 831 return 0; 832 } 833 #endif /* PAX_SEGVGUARD */ 834