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