2017-05-07 00:34:51 +03:00
|
|
|
/* $NetBSD: kern_pax.c,v 1.59 2017/05/06 21:34:51 joerg Exp $ */
|
2006-05-16 04:08:24 +04:00
|
|
|
|
Revamp PaX:
- don't confuse between ELF flags and proc flags. Introduce the proc-
specific P_PAX_ASLR, P_PAX_MPROTECT and P_PAX_GUARD flags.
- introduce pax_setup_elf_flags(), which takes as argument the PaX flag
of the ELF PaX note section, and which sets the proc flag as
appropriate. Also introduce a couple of other functions used for that
purpose.
- modify pax_aslr_active(), and all the other similar pieces of code, so
that it checks the proc flag directly, without extra ELF computation
In addition to making PaX clearer, the combination of these changes fixes
the following bug: if a non-PaX'ed process is launched, and then someone
sets security.pax.{aslr,mprotect,segvguard}.global=1, the process becomes
PaX'ed while its address space hasn't been randomized, which is not likely
to be a good idea.
Now, only the proc flag is checked at runtime, which means the process's
PaX status won't be altered during the execution.
Also:
- declare PAX_DPRINTF, makes it more readable
- fix a typo in exec_elf.h
2015-07-30 18:28:18 +03:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2015 The NetBSD Foundation, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
|
|
* by Maxime Villard.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2006-05-16 04:08:24 +04:00
|
|
|
* Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
2007-01-09 15:49:36 +03:00
|
|
|
* 3. The name of the author may not be used to endorse or promote products
|
2006-05-16 04:08:24 +04:00
|
|
|
* derived from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2007-09-21 23:14:12 +04:00
|
|
|
#include <sys/cdefs.h>
|
2017-05-07 00:34:51 +03:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: kern_pax.c,v 1.59 2017/05/06 21:34:51 joerg Exp $");
|
2007-09-21 23:14:12 +04:00
|
|
|
|
2006-05-16 04:08:24 +04:00
|
|
|
#include "opt_pax.h"
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/proc.h>
|
2015-10-09 05:00:59 +03:00
|
|
|
#include <sys/exec.h>
|
2006-05-16 04:08:24 +04:00
|
|
|
#include <sys/exec_elf.h>
|
|
|
|
#include <sys/pax.h>
|
|
|
|
#include <sys/sysctl.h>
|
2011-04-24 22:46:22 +04:00
|
|
|
#include <sys/kmem.h>
|
2016-03-19 21:56:37 +03:00
|
|
|
#include <sys/mman.h>
|
2006-11-22 05:02:51 +03:00
|
|
|
#include <sys/fileassoc.h>
|
|
|
|
#include <sys/syslog.h>
|
|
|
|
#include <sys/vnode.h>
|
|
|
|
#include <sys/queue.h>
|
2016-05-08 04:28:09 +03:00
|
|
|
#include <sys/bitops.h>
|
2006-11-22 05:02:51 +03:00
|
|
|
#include <sys/kauth.h>
|
First step of random number subsystem rework described in
<20111022023242.BA26F14A158@mail.netbsd.org>. This change includes
the following:
An initial cleanup and minor reorganization of the entropy pool
code in sys/dev/rnd.c and sys/dev/rndpool.c. Several bugs are
fixed. Some effort is made to accumulate entropy more quickly at
boot time.
A generic interface, "rndsink", is added, for stream generators to
request that they be re-keyed with good quality entropy from the pool
as soon as it is available.
The arc4random()/arc4randbytes() implementation in libkern is
adjusted to use the rndsink interface for rekeying, which helps
address the problem of low-quality keys at boot time.
An implementation of the FIPS 140-2 statistical tests for random
number generator quality is provided (libkern/rngtest.c). This
is based on Greg Rose's implementation from Qualcomm.
A new random stream generator, nist_ctr_drbg, is provided. It is
based on an implementation of the NIST SP800-90 CTR_DRBG by
Henric Jungheim. This generator users AES in a modified counter
mode to generate a backtracking-resistant random stream.
An abstraction layer, "cprng", is provided for in-kernel consumers
of randomness. The arc4random/arc4randbytes API is deprecated for
in-kernel use. It is replaced by "cprng_strong". The current
cprng_fast implementation wraps the existing arc4random
implementation. The current cprng_strong implementation wraps the
new CTR_DRBG implementation. Both interfaces are rekeyed from
the entropy pool automatically at intervals justifiable from best
current cryptographic practice.
In some quick tests, cprng_fast() is about the same speed as
the old arc4randbytes(), and cprng_strong() is about 20% faster
than rnd_extract_data(). Performance is expected to improve.
The AES code in src/crypto/rijndael is no longer an optional
kernel component, as it is required by cprng_strong, which is
not an optional kernel component.
The entropy pool output is subjected to the rngtest tests at
startup time; if it fails, the system will reboot. There is
approximately a 3/10000 chance of a false positive from these
tests. Entropy pool _input_ from hardware random numbers is
subjected to the rngtest tests at attach time, as well as the
FIPS continuous-output test, to detect bad or stuck hardware
RNGs; if any are detected, they are detached, but the system
continues to run.
A problem with rndctl(8) is fixed -- datastructures with
pointers in arrays are no longer passed to userspace (this
was not a security problem, but rather a major issue for
compat32). A new kernel will require a new rndctl.
The sysctl kern.arandom() and kern.urandom() nodes are hooked
up to the new generators, but the /dev/*random pseudodevices
are not, yet.
Manual pages for the new kernel interfaces are forthcoming.
2011-11-20 02:51:18 +04:00
|
|
|
#include <sys/cprng.h>
|
2006-05-16 04:08:24 +04:00
|
|
|
|
Revamp PaX:
- don't confuse between ELF flags and proc flags. Introduce the proc-
specific P_PAX_ASLR, P_PAX_MPROTECT and P_PAX_GUARD flags.
- introduce pax_setup_elf_flags(), which takes as argument the PaX flag
of the ELF PaX note section, and which sets the proc flag as
appropriate. Also introduce a couple of other functions used for that
purpose.
- modify pax_aslr_active(), and all the other similar pieces of code, so
that it checks the proc flag directly, without extra ELF computation
In addition to making PaX clearer, the combination of these changes fixes
the following bug: if a non-PaX'ed process is launched, and then someone
sets security.pax.{aslr,mprotect,segvguard}.global=1, the process becomes
PaX'ed while its address space hasn't been randomized, which is not likely
to be a good idea.
Now, only the proc flag is checked at runtime, which means the process's
PaX status won't be altered during the execution.
Also:
- declare PAX_DPRINTF, makes it more readable
- fix a typo in exec_elf.h
2015-07-30 18:28:18 +03:00
|
|
|
#ifdef PAX_ASLR_DEBUG
|
2016-03-19 21:56:37 +03:00
|
|
|
#define PAX_DPRINTF(_fmt, args...) \
|
|
|
|
do if (pax_aslr_debug) uprintf("%s: " _fmt "\n", __func__, ##args); \
|
|
|
|
while (/*CONSTCOND*/0)
|
Revamp PaX:
- don't confuse between ELF flags and proc flags. Introduce the proc-
specific P_PAX_ASLR, P_PAX_MPROTECT and P_PAX_GUARD flags.
- introduce pax_setup_elf_flags(), which takes as argument the PaX flag
of the ELF PaX note section, and which sets the proc flag as
appropriate. Also introduce a couple of other functions used for that
purpose.
- modify pax_aslr_active(), and all the other similar pieces of code, so
that it checks the proc flag directly, without extra ELF computation
In addition to making PaX clearer, the combination of these changes fixes
the following bug: if a non-PaX'ed process is launched, and then someone
sets security.pax.{aslr,mprotect,segvguard}.global=1, the process becomes
PaX'ed while its address space hasn't been randomized, which is not likely
to be a good idea.
Now, only the proc flag is checked at runtime, which means the process's
PaX status won't be altered during the execution.
Also:
- declare PAX_DPRINTF, makes it more readable
- fix a typo in exec_elf.h
2015-07-30 18:28:18 +03:00
|
|
|
#else
|
|
|
|
#define PAX_DPRINTF(_fmt, args...) do {} while (/*CONSTCOND*/0)
|
|
|
|
#endif
|
|
|
|
|
2007-12-27 01:11:47 +03:00
|
|
|
#ifdef PAX_ASLR
|
|
|
|
#include <sys/mman.h>
|
|
|
|
|
|
|
|
int pax_aslr_enabled = 1;
|
|
|
|
int pax_aslr_global = PAX_ASLR;
|
|
|
|
|
|
|
|
#ifndef PAX_ASLR_DELTA_MMAP_LSB
|
|
|
|
#define PAX_ASLR_DELTA_MMAP_LSB PGSHIFT
|
|
|
|
#endif
|
|
|
|
#ifndef PAX_ASLR_DELTA_MMAP_LEN
|
|
|
|
#define PAX_ASLR_DELTA_MMAP_LEN ((sizeof(void *) * NBBY) / 2)
|
|
|
|
#endif
|
2016-03-20 19:39:36 +03:00
|
|
|
#ifndef PAX_ASLR_DELTA_MMAP_LEN32
|
|
|
|
#define PAX_ASLR_DELTA_MMAP_LEN32 ((sizeof(uint32_t) * NBBY) / 2)
|
|
|
|
#endif
|
2007-12-27 01:11:47 +03:00
|
|
|
#ifndef PAX_ASLR_DELTA_STACK_LSB
|
|
|
|
#define PAX_ASLR_DELTA_STACK_LSB PGSHIFT
|
|
|
|
#endif
|
|
|
|
#ifndef PAX_ASLR_DELTA_STACK_LEN
|
2016-05-13 20:33:43 +03:00
|
|
|
#define PAX_ASLR_DELTA_STACK_LEN ((sizeof(void *) * NBBY) / 4)
|
2016-04-10 18:26:18 +03:00
|
|
|
#endif
|
|
|
|
#ifndef PAX_ASLR_DELTA_STACK_LEN32
|
2016-05-13 20:33:43 +03:00
|
|
|
#define PAX_ASLR_DELTA_STACK_LEN32 ((sizeof(uint32_t) * NBBY) / 4)
|
2007-12-27 01:11:47 +03:00
|
|
|
#endif
|
2016-05-13 20:33:43 +03:00
|
|
|
#define PAX_ASLR_MAX_STACK_WASTE 8
|
2007-12-27 01:11:47 +03:00
|
|
|
|
2016-09-17 05:29:11 +03:00
|
|
|
#ifdef PAX_ASLR_DEBUG
|
|
|
|
int pax_aslr_debug;
|
|
|
|
/* flag set means disable */
|
|
|
|
int pax_aslr_flags;
|
|
|
|
uint32_t pax_aslr_rand;
|
|
|
|
#define PAX_ASLR_STACK 0x01
|
|
|
|
#define PAX_ASLR_STACK_GAP 0x02
|
|
|
|
#define PAX_ASLR_MMAP 0x04
|
|
|
|
#define PAX_ASLR_EXEC_OFFSET 0x08
|
|
|
|
#define PAX_ASLR_RTLD_OFFSET 0x10
|
|
|
|
#define PAX_ASLR_FIXED 0x20
|
|
|
|
#endif
|
|
|
|
|
Revamp PaX:
- don't confuse between ELF flags and proc flags. Introduce the proc-
specific P_PAX_ASLR, P_PAX_MPROTECT and P_PAX_GUARD flags.
- introduce pax_setup_elf_flags(), which takes as argument the PaX flag
of the ELF PaX note section, and which sets the proc flag as
appropriate. Also introduce a couple of other functions used for that
purpose.
- modify pax_aslr_active(), and all the other similar pieces of code, so
that it checks the proc flag directly, without extra ELF computation
In addition to making PaX clearer, the combination of these changes fixes
the following bug: if a non-PaX'ed process is launched, and then someone
sets security.pax.{aslr,mprotect,segvguard}.global=1, the process becomes
PaX'ed while its address space hasn't been randomized, which is not likely
to be a good idea.
Now, only the proc flag is checked at runtime, which means the process's
PaX status won't be altered during the execution.
Also:
- declare PAX_DPRINTF, makes it more readable
- fix a typo in exec_elf.h
2015-07-30 18:28:18 +03:00
|
|
|
static bool pax_aslr_elf_flags_active(uint32_t);
|
2007-12-27 01:11:47 +03:00
|
|
|
#endif /* PAX_ASLR */
|
|
|
|
|
2006-11-22 03:41:38 +03:00
|
|
|
#ifdef PAX_MPROTECT
|
2006-11-01 12:36:28 +03:00
|
|
|
static int pax_mprotect_enabled = 1;
|
|
|
|
static int pax_mprotect_global = PAX_MPROTECT;
|
2016-05-25 23:07:54 +03:00
|
|
|
static int pax_mprotect_ptrace = 1;
|
Revamp PaX:
- don't confuse between ELF flags and proc flags. Introduce the proc-
specific P_PAX_ASLR, P_PAX_MPROTECT and P_PAX_GUARD flags.
- introduce pax_setup_elf_flags(), which takes as argument the PaX flag
of the ELF PaX note section, and which sets the proc flag as
appropriate. Also introduce a couple of other functions used for that
purpose.
- modify pax_aslr_active(), and all the other similar pieces of code, so
that it checks the proc flag directly, without extra ELF computation
In addition to making PaX clearer, the combination of these changes fixes
the following bug: if a non-PaX'ed process is launched, and then someone
sets security.pax.{aslr,mprotect,segvguard}.global=1, the process becomes
PaX'ed while its address space hasn't been randomized, which is not likely
to be a good idea.
Now, only the proc flag is checked at runtime, which means the process's
PaX status won't be altered during the execution.
Also:
- declare PAX_DPRINTF, makes it more readable
- fix a typo in exec_elf.h
2015-07-30 18:28:18 +03:00
|
|
|
static bool pax_mprotect_elf_flags_active(uint32_t);
|
2007-12-27 01:11:47 +03:00
|
|
|
#endif /* PAX_MPROTECT */
|
2016-04-07 06:31:12 +03:00
|
|
|
#ifdef PAX_MPROTECT_DEBUG
|
|
|
|
int pax_mprotect_debug;
|
|
|
|
#endif
|
2006-11-22 05:02:51 +03:00
|
|
|
|
|
|
|
#ifdef PAX_SEGVGUARD
|
|
|
|
#ifndef PAX_SEGVGUARD_EXPIRY
|
|
|
|
#define PAX_SEGVGUARD_EXPIRY (2 * 60)
|
|
|
|
#endif
|
|
|
|
#ifndef PAX_SEGVGUARD_SUSPENSION
|
|
|
|
#define PAX_SEGVGUARD_SUSPENSION (10 * 60)
|
|
|
|
#endif
|
|
|
|
#ifndef PAX_SEGVGUARD_MAXCRASHES
|
|
|
|
#define PAX_SEGVGUARD_MAXCRASHES 5
|
|
|
|
#endif
|
|
|
|
|
2016-03-19 21:56:37 +03:00
|
|
|
|
2006-11-22 05:02:51 +03:00
|
|
|
static int pax_segvguard_enabled = 1;
|
|
|
|
static int pax_segvguard_global = PAX_SEGVGUARD;
|
|
|
|
static int pax_segvguard_expiry = PAX_SEGVGUARD_EXPIRY;
|
|
|
|
static int pax_segvguard_suspension = PAX_SEGVGUARD_SUSPENSION;
|
|
|
|
static int pax_segvguard_maxcrashes = PAX_SEGVGUARD_MAXCRASHES;
|
|
|
|
|
|
|
|
static fileassoc_t segvguard_id;
|
|
|
|
|
|
|
|
struct pax_segvguard_uid_entry {
|
|
|
|
uid_t sue_uid;
|
|
|
|
size_t sue_ncrashes;
|
|
|
|
time_t sue_expiry;
|
|
|
|
time_t sue_suspended;
|
|
|
|
LIST_ENTRY(pax_segvguard_uid_entry) sue_list;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct pax_segvguard_entry {
|
|
|
|
LIST_HEAD(, pax_segvguard_uid_entry) segv_uids;
|
|
|
|
};
|
2006-12-23 11:35:43 +03:00
|
|
|
|
Revamp PaX:
- don't confuse between ELF flags and proc flags. Introduce the proc-
specific P_PAX_ASLR, P_PAX_MPROTECT and P_PAX_GUARD flags.
- introduce pax_setup_elf_flags(), which takes as argument the PaX flag
of the ELF PaX note section, and which sets the proc flag as
appropriate. Also introduce a couple of other functions used for that
purpose.
- modify pax_aslr_active(), and all the other similar pieces of code, so
that it checks the proc flag directly, without extra ELF computation
In addition to making PaX clearer, the combination of these changes fixes
the following bug: if a non-PaX'ed process is launched, and then someone
sets security.pax.{aslr,mprotect,segvguard}.global=1, the process becomes
PaX'ed while its address space hasn't been randomized, which is not likely
to be a good idea.
Now, only the proc flag is checked at runtime, which means the process's
PaX status won't be altered during the execution.
Also:
- declare PAX_DPRINTF, makes it more readable
- fix a typo in exec_elf.h
2015-07-30 18:28:18 +03:00
|
|
|
static bool pax_segvguard_elf_flags_active(uint32_t);
|
2015-08-04 21:28:09 +03:00
|
|
|
static void pax_segvguard_cleanup_cb(void *);
|
2006-11-22 05:02:51 +03:00
|
|
|
#endif /* PAX_SEGVGUARD */
|
2006-11-22 03:41:38 +03:00
|
|
|
|
2006-05-16 04:08:24 +04:00
|
|
|
SYSCTL_SETUP(sysctl_security_pax_setup, "sysctl security.pax setup")
|
|
|
|
{
|
2006-11-22 05:02:51 +03:00
|
|
|
const struct sysctlnode *rnode = NULL, *cnode;
|
2006-05-16 04:08:24 +04:00
|
|
|
|
2014-02-25 22:30:08 +04:00
|
|
|
sysctl_createv(clog, 0, NULL, &rnode,
|
2006-05-16 04:08:24 +04:00
|
|
|
CTLFLAG_PERMANENT,
|
|
|
|
CTLTYPE_NODE, "pax",
|
|
|
|
SYSCTL_DESCR("PaX (exploit mitigation) features."),
|
|
|
|
NULL, 0, NULL, 0,
|
2014-02-25 22:30:08 +04:00
|
|
|
CTL_SECURITY, CTL_CREATE, CTL_EOL);
|
2006-05-16 04:08:24 +04:00
|
|
|
|
2007-12-27 01:11:47 +03:00
|
|
|
cnode = rnode;
|
2007-12-27 18:21:52 +03:00
|
|
|
|
|
|
|
#ifdef PAX_MPROTECT
|
|
|
|
rnode = cnode;
|
2006-05-16 04:08:24 +04:00
|
|
|
sysctl_createv(clog, 0, &rnode, &rnode,
|
|
|
|
CTLFLAG_PERMANENT,
|
|
|
|
CTLTYPE_NODE, "mprotect",
|
|
|
|
SYSCTL_DESCR("mprotect(2) W^X restrictions."),
|
|
|
|
NULL, 0, NULL, 0,
|
|
|
|
CTL_CREATE, CTL_EOL);
|
|
|
|
sysctl_createv(clog, 0, &rnode, NULL,
|
2006-05-18 21:33:18 +04:00
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2006-05-16 04:08:24 +04:00
|
|
|
CTLTYPE_INT, "enabled",
|
|
|
|
SYSCTL_DESCR("Restrictions enabled."),
|
2006-05-18 21:33:18 +04:00
|
|
|
NULL, 0, &pax_mprotect_enabled, 0,
|
2006-05-16 04:08:24 +04:00
|
|
|
CTL_CREATE, CTL_EOL);
|
|
|
|
sysctl_createv(clog, 0, &rnode, NULL,
|
2006-05-18 21:33:18 +04:00
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
2006-09-26 18:48:40 +04:00
|
|
|
CTLTYPE_INT, "global",
|
2006-05-16 04:08:24 +04:00
|
|
|
SYSCTL_DESCR("When enabled, unless explicitly "
|
2006-10-26 00:55:11 +04:00
|
|
|
"specified, apply restrictions to "
|
2006-05-16 04:08:24 +04:00
|
|
|
"all processes."),
|
2006-05-18 21:33:18 +04:00
|
|
|
NULL, 0, &pax_mprotect_global, 0,
|
2006-05-16 04:08:24 +04:00
|
|
|
CTL_CREATE, CTL_EOL);
|
2016-05-25 20:43:58 +03:00
|
|
|
sysctl_createv(clog, 0, &rnode, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
|
|
|
CTLTYPE_INT, "ptrace",
|
|
|
|
SYSCTL_DESCR("When enabled, allow ptrace(2) to "
|
|
|
|
"override mprotect permissions on traced "
|
|
|
|
"processes"),
|
|
|
|
NULL, 0, &pax_mprotect_ptrace, 0,
|
|
|
|
CTL_CREATE, CTL_EOL);
|
2016-04-07 06:31:12 +03:00
|
|
|
#ifdef PAX_MPROTECT_DEBUG
|
|
|
|
sysctl_createv(clog, 0, &rnode, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
|
|
|
CTLTYPE_INT, "debug",
|
|
|
|
SYSCTL_DESCR("print mprotect changes."),
|
|
|
|
NULL, 0, &pax_mprotect_debug, 0,
|
|
|
|
CTL_CREATE, CTL_EOL);
|
|
|
|
#endif
|
2006-11-22 03:41:38 +03:00
|
|
|
#endif /* PAX_MPROTECT */
|
2006-11-22 05:02:51 +03:00
|
|
|
|
|
|
|
#ifdef PAX_SEGVGUARD
|
2007-12-27 01:11:47 +03:00
|
|
|
rnode = cnode;
|
2006-11-22 05:02:51 +03:00
|
|
|
sysctl_createv(clog, 0, &rnode, &rnode,
|
|
|
|
CTLFLAG_PERMANENT,
|
|
|
|
CTLTYPE_NODE, "segvguard",
|
|
|
|
SYSCTL_DESCR("PaX segvguard."),
|
|
|
|
NULL, 0, NULL, 0,
|
|
|
|
CTL_CREATE, CTL_EOL);
|
|
|
|
sysctl_createv(clog, 0, &rnode, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
|
|
|
CTLTYPE_INT, "enabled",
|
|
|
|
SYSCTL_DESCR("segvguard enabled."),
|
|
|
|
NULL, 0, &pax_segvguard_enabled, 0,
|
|
|
|
CTL_CREATE, CTL_EOL);
|
|
|
|
sysctl_createv(clog, 0, &rnode, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
|
|
|
CTLTYPE_INT, "global",
|
|
|
|
SYSCTL_DESCR("segvguard all programs."),
|
|
|
|
NULL, 0, &pax_segvguard_global, 0,
|
|
|
|
CTL_CREATE, CTL_EOL);
|
|
|
|
sysctl_createv(clog, 0, &rnode, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
|
|
|
CTLTYPE_INT, "expiry_timeout",
|
|
|
|
SYSCTL_DESCR("Entry expiry timeout (in seconds)."),
|
|
|
|
NULL, 0, &pax_segvguard_expiry, 0,
|
|
|
|
CTL_CREATE, CTL_EOL);
|
|
|
|
sysctl_createv(clog, 0, &rnode, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
|
|
|
CTLTYPE_INT, "suspend_timeout",
|
|
|
|
SYSCTL_DESCR("Entry suspension timeout (in seconds)."),
|
|
|
|
NULL, 0, &pax_segvguard_suspension, 0,
|
|
|
|
CTL_CREATE, CTL_EOL);
|
|
|
|
sysctl_createv(clog, 0, &rnode, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
|
|
|
CTLTYPE_INT, "max_crashes",
|
|
|
|
SYSCTL_DESCR("Max number of crashes before expiry."),
|
|
|
|
NULL, 0, &pax_segvguard_maxcrashes, 0,
|
|
|
|
CTL_CREATE, CTL_EOL);
|
|
|
|
#endif /* PAX_SEGVGUARD */
|
2007-12-27 01:11:47 +03:00
|
|
|
|
|
|
|
#ifdef PAX_ASLR
|
|
|
|
rnode = cnode;
|
|
|
|
sysctl_createv(clog, 0, &rnode, &rnode,
|
|
|
|
CTLFLAG_PERMANENT,
|
|
|
|
CTLTYPE_NODE, "aslr",
|
|
|
|
SYSCTL_DESCR("Address Space Layout Randomization."),
|
|
|
|
NULL, 0, NULL, 0,
|
|
|
|
CTL_CREATE, CTL_EOL);
|
|
|
|
sysctl_createv(clog, 0, &rnode, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
|
|
|
CTLTYPE_INT, "enabled",
|
|
|
|
SYSCTL_DESCR("Restrictions enabled."),
|
|
|
|
NULL, 0, &pax_aslr_enabled, 0,
|
|
|
|
CTL_CREATE, CTL_EOL);
|
|
|
|
sysctl_createv(clog, 0, &rnode, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
|
|
|
CTLTYPE_INT, "global",
|
|
|
|
SYSCTL_DESCR("When enabled, unless explicitly "
|
|
|
|
"specified, apply to all processes."),
|
|
|
|
NULL, 0, &pax_aslr_global, 0,
|
|
|
|
CTL_CREATE, CTL_EOL);
|
2016-03-19 21:56:37 +03:00
|
|
|
#ifdef PAX_ASLR_DEBUG
|
|
|
|
sysctl_createv(clog, 0, &rnode, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
|
|
|
CTLTYPE_INT, "debug",
|
|
|
|
SYSCTL_DESCR("Pring ASLR selected addresses."),
|
|
|
|
NULL, 0, &pax_aslr_debug, 0,
|
|
|
|
CTL_CREATE, CTL_EOL);
|
2016-04-10 18:02:17 +03:00
|
|
|
sysctl_createv(clog, 0, &rnode, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
|
|
|
CTLTYPE_INT, "flags",
|
|
|
|
SYSCTL_DESCR("Disable/Enable select ASLR features."),
|
|
|
|
NULL, 0, &pax_aslr_flags, 0,
|
|
|
|
CTL_CREATE, CTL_EOL);
|
2016-05-08 04:28:09 +03:00
|
|
|
sysctl_createv(clog, 0, &rnode, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
|
|
|
|
CTLTYPE_INT, "rand",
|
|
|
|
SYSCTL_DESCR("Use the given fixed random value"),
|
|
|
|
NULL, 0, &pax_aslr_rand, 0,
|
|
|
|
CTL_CREATE, CTL_EOL);
|
2016-03-19 21:56:37 +03:00
|
|
|
#endif
|
2007-12-27 01:11:47 +03:00
|
|
|
sysctl_createv(clog, 0, &rnode, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
|
|
|
|
CTLTYPE_INT, "mmap_len",
|
|
|
|
SYSCTL_DESCR("Number of bits randomized for "
|
|
|
|
"mmap(2) calls."),
|
|
|
|
NULL, PAX_ASLR_DELTA_MMAP_LEN, NULL, 0,
|
|
|
|
CTL_CREATE, CTL_EOL);
|
2007-12-27 18:21:52 +03:00
|
|
|
sysctl_createv(clog, 0, &rnode, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
|
|
|
|
CTLTYPE_INT, "stack_len",
|
|
|
|
SYSCTL_DESCR("Number of bits randomized for "
|
|
|
|
"the stack."),
|
|
|
|
NULL, PAX_ASLR_DELTA_STACK_LEN, NULL, 0,
|
|
|
|
CTL_CREATE, CTL_EOL);
|
|
|
|
sysctl_createv(clog, 0, &rnode, NULL,
|
|
|
|
CTLFLAG_PERMANENT|CTLFLAG_IMMEDIATE,
|
|
|
|
CTLTYPE_INT, "exec_len",
|
|
|
|
SYSCTL_DESCR("Number of bits randomized for "
|
|
|
|
"the PIE exec base."),
|
|
|
|
NULL, PAX_ASLR_DELTA_EXEC_LEN, NULL, 0,
|
|
|
|
CTL_CREATE, CTL_EOL);
|
|
|
|
|
2007-12-27 01:11:47 +03:00
|
|
|
#endif /* PAX_ASLR */
|
2006-05-16 04:08:24 +04:00
|
|
|
}
|
|
|
|
|
2006-11-22 03:41:38 +03:00
|
|
|
/*
|
|
|
|
* Initialize PaX.
|
|
|
|
*/
|
2006-05-16 04:08:24 +04:00
|
|
|
void
|
2006-11-22 03:41:38 +03:00
|
|
|
pax_init(void)
|
2006-05-16 04:08:24 +04:00
|
|
|
{
|
2006-12-11 18:24:27 +03:00
|
|
|
#ifdef PAX_SEGVGUARD
|
|
|
|
int error;
|
|
|
|
|
2015-08-04 21:28:09 +03:00
|
|
|
error = fileassoc_register("segvguard", pax_segvguard_cleanup_cb,
|
2006-12-11 18:24:27 +03:00
|
|
|
&segvguard_id);
|
|
|
|
if (error) {
|
|
|
|
panic("pax_init: segvguard_id: error=%d\n", error);
|
|
|
|
}
|
2006-11-22 05:02:51 +03:00
|
|
|
#endif /* PAX_SEGVGUARD */
|
2016-05-13 20:33:43 +03:00
|
|
|
#ifdef PAX_ASLR
|
|
|
|
/* Adjust maximum stack by the size we can consume for ASLR */
|
|
|
|
extern rlim_t maxsmap;
|
|
|
|
maxsmap = MAXSSIZ - (MAXSSIZ / PAX_ASLR_MAX_STACK_WASTE);
|
|
|
|
// XXX: compat32 is not handled.
|
|
|
|
#endif
|
2006-05-16 04:08:24 +04:00
|
|
|
}
|
|
|
|
|
2016-05-25 23:07:54 +03:00
|
|
|
void
|
|
|
|
pax_set_flags(struct exec_package *epp, struct proc *p)
|
|
|
|
{
|
|
|
|
p->p_pax = epp->ep_pax_flags;
|
|
|
|
|
2016-05-27 19:35:16 +03:00
|
|
|
#ifdef PAX_MPROTECT
|
2016-05-25 23:07:54 +03:00
|
|
|
if (pax_mprotect_ptrace == 0)
|
|
|
|
return;
|
|
|
|
/*
|
2016-05-25 23:49:00 +03:00
|
|
|
* If we are running under the debugger, turn off MPROTECT so
|
2016-05-25 23:07:54 +03:00
|
|
|
* the debugger can insert/delete breakpoints
|
|
|
|
*/
|
|
|
|
if (p->p_slflag & PSL_TRACED)
|
|
|
|
p->p_pax &= ~P_PAX_MPROTECT;
|
2016-05-27 19:35:16 +03:00
|
|
|
#endif
|
2016-05-25 23:07:54 +03:00
|
|
|
}
|
|
|
|
|
2006-05-16 04:08:24 +04:00
|
|
|
void
|
2015-09-26 19:12:24 +03:00
|
|
|
pax_setup_elf_flags(struct exec_package *epp, uint32_t elf_flags)
|
2006-05-16 04:08:24 +04:00
|
|
|
{
|
Revamp PaX:
- don't confuse between ELF flags and proc flags. Introduce the proc-
specific P_PAX_ASLR, P_PAX_MPROTECT and P_PAX_GUARD flags.
- introduce pax_setup_elf_flags(), which takes as argument the PaX flag
of the ELF PaX note section, and which sets the proc flag as
appropriate. Also introduce a couple of other functions used for that
purpose.
- modify pax_aslr_active(), and all the other similar pieces of code, so
that it checks the proc flag directly, without extra ELF computation
In addition to making PaX clearer, the combination of these changes fixes
the following bug: if a non-PaX'ed process is launched, and then someone
sets security.pax.{aslr,mprotect,segvguard}.global=1, the process becomes
PaX'ed while its address space hasn't been randomized, which is not likely
to be a good idea.
Now, only the proc flag is checked at runtime, which means the process's
PaX status won't be altered during the execution.
Also:
- declare PAX_DPRINTF, makes it more readable
- fix a typo in exec_elf.h
2015-07-30 18:28:18 +03:00
|
|
|
uint32_t flags = 0;
|
|
|
|
|
|
|
|
#ifdef PAX_ASLR
|
|
|
|
if (pax_aslr_elf_flags_active(elf_flags)) {
|
|
|
|
flags |= P_PAX_ASLR;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef PAX_MPROTECT
|
|
|
|
if (pax_mprotect_elf_flags_active(elf_flags)) {
|
|
|
|
flags |= P_PAX_MPROTECT;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef PAX_SEGVGUARD
|
|
|
|
if (pax_segvguard_elf_flags_active(elf_flags)) {
|
|
|
|
flags |= P_PAX_GUARD;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-09-26 19:12:24 +03:00
|
|
|
epp->ep_pax_flags = flags;
|
Revamp PaX:
- don't confuse between ELF flags and proc flags. Introduce the proc-
specific P_PAX_ASLR, P_PAX_MPROTECT and P_PAX_GUARD flags.
- introduce pax_setup_elf_flags(), which takes as argument the PaX flag
of the ELF PaX note section, and which sets the proc flag as
appropriate. Also introduce a couple of other functions used for that
purpose.
- modify pax_aslr_active(), and all the other similar pieces of code, so
that it checks the proc flag directly, without extra ELF computation
In addition to making PaX clearer, the combination of these changes fixes
the following bug: if a non-PaX'ed process is launched, and then someone
sets security.pax.{aslr,mprotect,segvguard}.global=1, the process becomes
PaX'ed while its address space hasn't been randomized, which is not likely
to be a good idea.
Now, only the proc flag is checked at runtime, which means the process's
PaX status won't be altered during the execution.
Also:
- declare PAX_DPRINTF, makes it more readable
- fix a typo in exec_elf.h
2015-07-30 18:28:18 +03:00
|
|
|
}
|
|
|
|
|
2015-08-04 21:28:09 +03:00
|
|
|
#if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD) || defined(PAX_ASLR)
|
|
|
|
static inline bool
|
|
|
|
pax_flags_active(uint32_t flags, uint32_t opt)
|
|
|
|
{
|
|
|
|
if (!(flags & opt))
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#endif /* PAX_MPROTECT || PAX_SEGVGUARD || PAX_ASLR */
|
2006-11-22 03:41:38 +03:00
|
|
|
|
Revamp PaX:
- don't confuse between ELF flags and proc flags. Introduce the proc-
specific P_PAX_ASLR, P_PAX_MPROTECT and P_PAX_GUARD flags.
- introduce pax_setup_elf_flags(), which takes as argument the PaX flag
of the ELF PaX note section, and which sets the proc flag as
appropriate. Also introduce a couple of other functions used for that
purpose.
- modify pax_aslr_active(), and all the other similar pieces of code, so
that it checks the proc flag directly, without extra ELF computation
In addition to making PaX clearer, the combination of these changes fixes
the following bug: if a non-PaX'ed process is launched, and then someone
sets security.pax.{aslr,mprotect,segvguard}.global=1, the process becomes
PaX'ed while its address space hasn't been randomized, which is not likely
to be a good idea.
Now, only the proc flag is checked at runtime, which means the process's
PaX status won't be altered during the execution.
Also:
- declare PAX_DPRINTF, makes it more readable
- fix a typo in exec_elf.h
2015-07-30 18:28:18 +03:00
|
|
|
#ifdef PAX_MPROTECT
|
|
|
|
static bool
|
|
|
|
pax_mprotect_elf_flags_active(uint32_t flags)
|
|
|
|
{
|
2006-11-22 03:41:38 +03:00
|
|
|
if (!pax_mprotect_enabled)
|
Revamp PaX:
- don't confuse between ELF flags and proc flags. Introduce the proc-
specific P_PAX_ASLR, P_PAX_MPROTECT and P_PAX_GUARD flags.
- introduce pax_setup_elf_flags(), which takes as argument the PaX flag
of the ELF PaX note section, and which sets the proc flag as
appropriate. Also introduce a couple of other functions used for that
purpose.
- modify pax_aslr_active(), and all the other similar pieces of code, so
that it checks the proc flag directly, without extra ELF computation
In addition to making PaX clearer, the combination of these changes fixes
the following bug: if a non-PaX'ed process is launched, and then someone
sets security.pax.{aslr,mprotect,segvguard}.global=1, the process becomes
PaX'ed while its address space hasn't been randomized, which is not likely
to be a good idea.
Now, only the proc flag is checked at runtime, which means the process's
PaX status won't be altered during the execution.
Also:
- declare PAX_DPRINTF, makes it more readable
- fix a typo in exec_elf.h
2015-07-30 18:28:18 +03:00
|
|
|
return false;
|
|
|
|
if (pax_mprotect_global && (flags & ELF_NOTE_PAX_NOMPROTECT) != 0) {
|
|
|
|
/* Mprotect explicitly disabled */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!pax_mprotect_global && (flags & ELF_NOTE_PAX_MPROTECT) == 0) {
|
|
|
|
/* Mprotect not requested */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2006-11-22 03:41:38 +03:00
|
|
|
|
2017-05-07 00:34:51 +03:00
|
|
|
vm_prot_t
|
|
|
|
pax_mprotect_maxprotect(
|
2016-04-07 06:31:12 +03:00
|
|
|
#ifdef PAX_MPROTECT_DEBUG
|
|
|
|
const char *file, size_t line,
|
|
|
|
#endif
|
2017-05-07 00:34:51 +03:00
|
|
|
struct lwp *l, vm_prot_t active, vm_prot_t extra, vm_prot_t maxprot)
|
Revamp PaX:
- don't confuse between ELF flags and proc flags. Introduce the proc-
specific P_PAX_ASLR, P_PAX_MPROTECT and P_PAX_GUARD flags.
- introduce pax_setup_elf_flags(), which takes as argument the PaX flag
of the ELF PaX note section, and which sets the proc flag as
appropriate. Also introduce a couple of other functions used for that
purpose.
- modify pax_aslr_active(), and all the other similar pieces of code, so
that it checks the proc flag directly, without extra ELF computation
In addition to making PaX clearer, the combination of these changes fixes
the following bug: if a non-PaX'ed process is launched, and then someone
sets security.pax.{aslr,mprotect,segvguard}.global=1, the process becomes
PaX'ed while its address space hasn't been randomized, which is not likely
to be a good idea.
Now, only the proc flag is checked at runtime, which means the process's
PaX status won't be altered during the execution.
Also:
- declare PAX_DPRINTF, makes it more readable
- fix a typo in exec_elf.h
2015-07-30 18:28:18 +03:00
|
|
|
{
|
|
|
|
uint32_t flags;
|
|
|
|
|
|
|
|
flags = l->l_proc->p_pax;
|
2015-08-04 21:28:09 +03:00
|
|
|
if (!pax_flags_active(flags, P_PAX_MPROTECT))
|
2017-05-07 00:34:51 +03:00
|
|
|
return maxprot;
|
2006-05-16 04:08:24 +04:00
|
|
|
|
2017-05-07 00:34:51 +03:00
|
|
|
return (active|extra) & maxprot;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pax_mprotect_validate(
|
2016-04-07 06:31:12 +03:00
|
|
|
#ifdef PAX_MPROTECT_DEBUG
|
2017-05-07 00:34:51 +03:00
|
|
|
const char *file, size_t line,
|
2016-04-04 19:47:39 +03:00
|
|
|
#endif
|
2017-05-07 00:34:51 +03:00
|
|
|
struct lwp *l, vm_prot_t prot)
|
|
|
|
{
|
|
|
|
uint32_t flags;
|
|
|
|
|
|
|
|
flags = l->l_proc->p_pax;
|
|
|
|
if (!pax_flags_active(flags, P_PAX_MPROTECT))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if ((prot & (VM_PROT_WRITE|VM_PROT_EXECUTE)) ==
|
|
|
|
(VM_PROT_WRITE|VM_PROT_EXECUTE)) {
|
2016-04-07 06:31:12 +03:00
|
|
|
#ifdef PAX_MPROTECT_DEBUG
|
2016-04-04 19:47:39 +03:00
|
|
|
struct proc *p = l->l_proc;
|
2017-05-07 00:34:51 +03:00
|
|
|
|
|
|
|
if (pax_mprotect_debug)
|
|
|
|
printf("%s: %s,%zu: %d.%d (%s): WX rejected\n",
|
2016-04-07 06:31:12 +03:00
|
|
|
__func__, file, line,
|
|
|
|
p->p_pid, l->l_lid, p->p_comm);
|
2016-04-04 19:47:39 +03:00
|
|
|
#endif
|
2017-05-07 00:34:51 +03:00
|
|
|
return EACCES;
|
2006-05-16 04:08:24 +04:00
|
|
|
}
|
2017-05-07 00:34:51 +03:00
|
|
|
return 0;
|
2006-05-16 04:08:24 +04:00
|
|
|
}
|
2016-05-25 20:43:58 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Bypass MPROTECT for traced processes
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
pax_mprotect_prot(struct lwp *l)
|
|
|
|
{
|
|
|
|
uint32_t flags;
|
|
|
|
|
|
|
|
flags = l->l_proc->p_pax;
|
|
|
|
if (!pax_flags_active(flags, P_PAX_MPROTECT))
|
|
|
|
return 0;
|
2016-05-25 23:07:54 +03:00
|
|
|
if (pax_mprotect_ptrace < 2)
|
2016-05-25 20:43:58 +03:00
|
|
|
return 0;
|
|
|
|
return UVM_EXTRACT_PROT_ALL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-11-22 03:41:38 +03:00
|
|
|
#endif /* PAX_MPROTECT */
|
2006-11-22 05:02:51 +03:00
|
|
|
|
2007-12-27 01:11:47 +03:00
|
|
|
#ifdef PAX_ASLR
|
Revamp PaX:
- don't confuse between ELF flags and proc flags. Introduce the proc-
specific P_PAX_ASLR, P_PAX_MPROTECT and P_PAX_GUARD flags.
- introduce pax_setup_elf_flags(), which takes as argument the PaX flag
of the ELF PaX note section, and which sets the proc flag as
appropriate. Also introduce a couple of other functions used for that
purpose.
- modify pax_aslr_active(), and all the other similar pieces of code, so
that it checks the proc flag directly, without extra ELF computation
In addition to making PaX clearer, the combination of these changes fixes
the following bug: if a non-PaX'ed process is launched, and then someone
sets security.pax.{aslr,mprotect,segvguard}.global=1, the process becomes
PaX'ed while its address space hasn't been randomized, which is not likely
to be a good idea.
Now, only the proc flag is checked at runtime, which means the process's
PaX status won't be altered during the execution.
Also:
- declare PAX_DPRINTF, makes it more readable
- fix a typo in exec_elf.h
2015-07-30 18:28:18 +03:00
|
|
|
static bool
|
|
|
|
pax_aslr_elf_flags_active(uint32_t flags)
|
2007-12-27 01:11:47 +03:00
|
|
|
{
|
|
|
|
if (!pax_aslr_enabled)
|
|
|
|
return false;
|
Revamp PaX:
- don't confuse between ELF flags and proc flags. Introduce the proc-
specific P_PAX_ASLR, P_PAX_MPROTECT and P_PAX_GUARD flags.
- introduce pax_setup_elf_flags(), which takes as argument the PaX flag
of the ELF PaX note section, and which sets the proc flag as
appropriate. Also introduce a couple of other functions used for that
purpose.
- modify pax_aslr_active(), and all the other similar pieces of code, so
that it checks the proc flag directly, without extra ELF computation
In addition to making PaX clearer, the combination of these changes fixes
the following bug: if a non-PaX'ed process is launched, and then someone
sets security.pax.{aslr,mprotect,segvguard}.global=1, the process becomes
PaX'ed while its address space hasn't been randomized, which is not likely
to be a good idea.
Now, only the proc flag is checked at runtime, which means the process's
PaX status won't be altered during the execution.
Also:
- declare PAX_DPRINTF, makes it more readable
- fix a typo in exec_elf.h
2015-07-30 18:28:18 +03:00
|
|
|
if (pax_aslr_global && (flags & ELF_NOTE_PAX_NOASLR) != 0) {
|
|
|
|
/* ASLR explicitly disabled */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!pax_aslr_global && (flags & ELF_NOTE_PAX_ASLR) == 0) {
|
|
|
|
/* ASLR not requested */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2007-12-27 01:11:47 +03:00
|
|
|
|
2016-05-22 17:26:09 +03:00
|
|
|
static bool
|
2015-09-26 19:12:24 +03:00
|
|
|
pax_aslr_epp_active(struct exec_package *epp)
|
|
|
|
{
|
2016-05-24 20:30:01 +03:00
|
|
|
if (__predict_false((epp->ep_flags & (EXEC_32|EXEC_TOPDOWN_VM)) == 0))
|
|
|
|
return false;
|
2015-09-26 19:12:24 +03:00
|
|
|
return pax_flags_active(epp->ep_pax_flags, P_PAX_ASLR);
|
|
|
|
}
|
|
|
|
|
2016-05-22 17:26:09 +03:00
|
|
|
static bool
|
Revamp PaX:
- don't confuse between ELF flags and proc flags. Introduce the proc-
specific P_PAX_ASLR, P_PAX_MPROTECT and P_PAX_GUARD flags.
- introduce pax_setup_elf_flags(), which takes as argument the PaX flag
of the ELF PaX note section, and which sets the proc flag as
appropriate. Also introduce a couple of other functions used for that
purpose.
- modify pax_aslr_active(), and all the other similar pieces of code, so
that it checks the proc flag directly, without extra ELF computation
In addition to making PaX clearer, the combination of these changes fixes
the following bug: if a non-PaX'ed process is launched, and then someone
sets security.pax.{aslr,mprotect,segvguard}.global=1, the process becomes
PaX'ed while its address space hasn't been randomized, which is not likely
to be a good idea.
Now, only the proc flag is checked at runtime, which means the process's
PaX status won't be altered during the execution.
Also:
- declare PAX_DPRINTF, makes it more readable
- fix a typo in exec_elf.h
2015-07-30 18:28:18 +03:00
|
|
|
pax_aslr_active(struct lwp *l)
|
|
|
|
{
|
2015-08-04 21:28:09 +03:00
|
|
|
return pax_flags_active(l->l_proc->p_pax, P_PAX_ASLR);
|
2007-12-27 01:11:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2016-03-20 17:58:10 +03:00
|
|
|
pax_aslr_init_vm(struct lwp *l, struct vmspace *vm, struct exec_package *ep)
|
2007-12-27 01:11:47 +03:00
|
|
|
{
|
|
|
|
if (!pax_aslr_active(l))
|
|
|
|
return;
|
|
|
|
|
2016-05-24 20:30:01 +03:00
|
|
|
if (__predict_false((ep->ep_flags & (EXEC_32|EXEC_TOPDOWN_VM)) == 0))
|
|
|
|
return;
|
|
|
|
|
2016-04-10 18:02:17 +03:00
|
|
|
#ifdef PAX_ASLR_DEBUG
|
|
|
|
if (pax_aslr_flags & PAX_ASLR_MMAP)
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
|
2016-03-20 19:39:36 +03:00
|
|
|
uint32_t len = (ep->ep_flags & EXEC_32) ?
|
|
|
|
PAX_ASLR_DELTA_MMAP_LEN32 : PAX_ASLR_DELTA_MMAP_LEN;
|
|
|
|
|
2016-05-08 04:28:09 +03:00
|
|
|
uint32_t rand = cprng_fast32();
|
|
|
|
#ifdef PAX_ASLR_DEBUG
|
|
|
|
if (pax_aslr_flags & PAX_ASLR_FIXED)
|
|
|
|
rand = pax_aslr_rand;
|
|
|
|
#endif
|
|
|
|
vm->vm_aslr_delta_mmap = PAX_ASLR_DELTA(rand,
|
2016-03-20 19:39:36 +03:00
|
|
|
PAX_ASLR_DELTA_MMAP_LSB, len);
|
|
|
|
|
2016-05-20 00:39:15 +03:00
|
|
|
PAX_DPRINTF("delta_mmap=%#jx/%u",
|
|
|
|
(uintmax_t)vm->vm_aslr_delta_mmap, len);
|
2007-12-27 01:11:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-08-04 21:28:09 +03:00
|
|
|
pax_aslr_mmap(struct lwp *l, vaddr_t *addr, vaddr_t orig_addr, int f)
|
2007-12-27 01:11:47 +03:00
|
|
|
{
|
|
|
|
if (!pax_aslr_active(l))
|
|
|
|
return;
|
2016-03-19 21:56:37 +03:00
|
|
|
#ifdef PAX_ASLR_DEBUG
|
|
|
|
char buf[256];
|
2016-04-10 18:02:17 +03:00
|
|
|
|
|
|
|
if (pax_aslr_flags & PAX_ASLR_MMAP)
|
|
|
|
return;
|
|
|
|
|
2016-03-19 21:56:37 +03:00
|
|
|
if (pax_aslr_debug)
|
|
|
|
snprintb(buf, sizeof(buf), MAP_FMT, f);
|
|
|
|
else
|
|
|
|
buf[0] = '\0';
|
|
|
|
#endif
|
2007-12-27 01:11:47 +03:00
|
|
|
|
|
|
|
if (!(f & MAP_FIXED) && ((orig_addr == 0) || !(f & MAP_ANON))) {
|
2016-03-19 21:56:37 +03:00
|
|
|
PAX_DPRINTF("applying to %#jx orig_addr=%#jx f=%s",
|
|
|
|
(uintmax_t)*addr, (uintmax_t)orig_addr, buf);
|
2007-12-27 01:11:47 +03:00
|
|
|
if (!(l->l_proc->p_vmspace->vm_map.flags & VM_MAP_TOPDOWN))
|
|
|
|
*addr += l->l_proc->p_vmspace->vm_aslr_delta_mmap;
|
|
|
|
else
|
|
|
|
*addr -= l->l_proc->p_vmspace->vm_aslr_delta_mmap;
|
2016-03-19 21:56:37 +03:00
|
|
|
PAX_DPRINTF("result %#jx", (uintmax_t)*addr);
|
Revamp PaX:
- don't confuse between ELF flags and proc flags. Introduce the proc-
specific P_PAX_ASLR, P_PAX_MPROTECT and P_PAX_GUARD flags.
- introduce pax_setup_elf_flags(), which takes as argument the PaX flag
of the ELF PaX note section, and which sets the proc flag as
appropriate. Also introduce a couple of other functions used for that
purpose.
- modify pax_aslr_active(), and all the other similar pieces of code, so
that it checks the proc flag directly, without extra ELF computation
In addition to making PaX clearer, the combination of these changes fixes
the following bug: if a non-PaX'ed process is launched, and then someone
sets security.pax.{aslr,mprotect,segvguard}.global=1, the process becomes
PaX'ed while its address space hasn't been randomized, which is not likely
to be a good idea.
Now, only the proc flag is checked at runtime, which means the process's
PaX status won't be altered during the execution.
Also:
- declare PAX_DPRINTF, makes it more readable
- fix a typo in exec_elf.h
2015-07-30 18:28:18 +03:00
|
|
|
} else {
|
2016-03-19 21:56:37 +03:00
|
|
|
PAX_DPRINTF("not applying to %#jx orig_addr=%#jx f=%s",
|
|
|
|
(uintmax_t)*addr, (uintmax_t)orig_addr, buf);
|
2007-12-27 01:11:47 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-25 20:25:32 +03:00
|
|
|
static vaddr_t
|
|
|
|
pax_aslr_offset(vaddr_t align)
|
2016-05-08 04:28:09 +03:00
|
|
|
{
|
|
|
|
size_t pax_align, l2, delta;
|
|
|
|
uint32_t rand;
|
|
|
|
vaddr_t offset;
|
|
|
|
|
2017-02-18 04:29:09 +03:00
|
|
|
pax_align = align == 0 ? PAGE_SIZE : align;
|
2016-05-08 04:28:09 +03:00
|
|
|
l2 = ilog2(pax_align);
|
|
|
|
|
|
|
|
rand = cprng_fast32();
|
|
|
|
#ifdef PAX_ASLR_DEBUG
|
|
|
|
if (pax_aslr_flags & PAX_ASLR_FIXED)
|
|
|
|
rand = pax_aslr_rand;
|
|
|
|
#endif
|
2016-05-25 20:25:32 +03:00
|
|
|
|
|
|
|
#define PAX_TRUNC(a, b) ((a) & ~((b) - 1))
|
|
|
|
|
2016-05-08 04:28:09 +03:00
|
|
|
delta = PAX_ASLR_DELTA(rand, l2, PAX_ASLR_DELTA_EXEC_LEN);
|
2017-02-18 04:29:09 +03:00
|
|
|
offset = PAX_TRUNC(delta, pax_align);
|
|
|
|
offset = MAX(offset, pax_align);
|
2016-05-08 04:28:09 +03:00
|
|
|
|
|
|
|
PAX_DPRINTF("rand=%#x l2=%#zx pax_align=%#zx delta=%#zx offset=%#jx",
|
|
|
|
rand, l2, pax_align, delta, (uintmax_t)offset);
|
2016-05-25 20:25:32 +03:00
|
|
|
|
2016-05-08 04:28:09 +03:00
|
|
|
return offset;
|
2016-05-25 20:25:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
vaddr_t
|
|
|
|
pax_aslr_exec_offset(struct exec_package *epp, vaddr_t align)
|
|
|
|
{
|
|
|
|
if (!pax_aslr_epp_active(epp))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
#ifdef PAX_ASLR_DEBUG
|
|
|
|
if (pax_aslr_flags & PAX_ASLR_EXEC_OFFSET)
|
|
|
|
goto out;
|
|
|
|
#endif
|
2017-02-18 04:29:09 +03:00
|
|
|
return pax_aslr_offset(align);
|
2016-05-08 04:28:09 +03:00
|
|
|
out:
|
2017-02-18 04:29:09 +03:00
|
|
|
return 0;
|
2016-05-08 04:28:09 +03:00
|
|
|
}
|
|
|
|
|
2016-05-25 20:25:32 +03:00
|
|
|
voff_t
|
|
|
|
pax_aslr_rtld_offset(struct exec_package *epp, vaddr_t align, int use_topdown)
|
|
|
|
{
|
|
|
|
voff_t offset;
|
|
|
|
|
|
|
|
if (!pax_aslr_epp_active(epp))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#ifdef PAX_ASLR_DEBUG
|
|
|
|
if (pax_aslr_flags & PAX_ASLR_RTLD_OFFSET)
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
offset = pax_aslr_offset(align);
|
|
|
|
if (use_topdown)
|
|
|
|
offset = -offset;
|
|
|
|
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
2007-12-27 01:11:47 +03:00
|
|
|
void
|
2016-09-03 15:20:58 +03:00
|
|
|
pax_aslr_stack(struct exec_package *epp, vsize_t *max_stack_size)
|
2007-12-27 01:11:47 +03:00
|
|
|
{
|
2015-09-26 19:12:24 +03:00
|
|
|
if (!pax_aslr_epp_active(epp))
|
2015-08-04 21:28:09 +03:00
|
|
|
return;
|
2016-04-10 18:02:17 +03:00
|
|
|
#ifdef PAX_ASLR_DEBUG
|
|
|
|
if (pax_aslr_flags & PAX_ASLR_STACK)
|
|
|
|
return;
|
|
|
|
#endif
|
2015-08-04 21:28:09 +03:00
|
|
|
|
2016-04-10 18:26:18 +03:00
|
|
|
uint32_t len = (epp->ep_flags & EXEC_32) ?
|
|
|
|
PAX_ASLR_DELTA_STACK_LEN32 : PAX_ASLR_DELTA_STACK_LEN;
|
2016-05-08 04:28:09 +03:00
|
|
|
uint32_t rand = cprng_fast32();
|
|
|
|
#ifdef PAX_ASLR_DEBUG
|
|
|
|
if (pax_aslr_flags & PAX_ASLR_FIXED)
|
|
|
|
rand = pax_aslr_rand;
|
|
|
|
#endif
|
|
|
|
u_long d = PAX_ASLR_DELTA(rand, PAX_ASLR_DELTA_STACK_LSB, len);
|
2016-05-13 20:33:43 +03:00
|
|
|
d &= (*max_stack_size / PAX_ASLR_MAX_STACK_WASTE) - 1;
|
2016-05-08 23:01:56 +03:00
|
|
|
u_long newminsaddr = (u_long)STACK_GROW(epp->ep_minsaddr, d);
|
2016-04-10 18:26:18 +03:00
|
|
|
PAX_DPRINTF("old minsaddr=%#jx delta=%#lx new minsaddr=%#lx",
|
|
|
|
(uintmax_t)epp->ep_minsaddr, d, newminsaddr);
|
|
|
|
epp->ep_minsaddr = (vaddr_t)newminsaddr;
|
2015-08-04 21:28:09 +03:00
|
|
|
*max_stack_size -= d;
|
2007-12-27 01:11:47 +03:00
|
|
|
}
|
2016-05-08 04:28:09 +03:00
|
|
|
|
|
|
|
uint32_t
|
|
|
|
pax_aslr_stack_gap(struct exec_package *epp)
|
|
|
|
{
|
|
|
|
if (!pax_aslr_epp_active(epp))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#ifdef PAX_ASLR_DEBUG
|
|
|
|
if (pax_aslr_flags & PAX_ASLR_STACK_GAP)
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
uint32_t rand = cprng_fast32();
|
|
|
|
#ifdef PAX_ASLR_DEBUG
|
|
|
|
if (pax_aslr_flags & PAX_ASLR_FIXED)
|
|
|
|
rand = pax_aslr_rand;
|
|
|
|
#endif
|
|
|
|
rand %= PAGE_SIZE;
|
|
|
|
PAX_DPRINTF("stack gap=%#x\n", rand);
|
|
|
|
return rand;
|
|
|
|
}
|
2007-12-27 01:11:47 +03:00
|
|
|
#endif /* PAX_ASLR */
|
|
|
|
|
2006-11-22 05:02:51 +03:00
|
|
|
#ifdef PAX_SEGVGUARD
|
Revamp PaX:
- don't confuse between ELF flags and proc flags. Introduce the proc-
specific P_PAX_ASLR, P_PAX_MPROTECT and P_PAX_GUARD flags.
- introduce pax_setup_elf_flags(), which takes as argument the PaX flag
of the ELF PaX note section, and which sets the proc flag as
appropriate. Also introduce a couple of other functions used for that
purpose.
- modify pax_aslr_active(), and all the other similar pieces of code, so
that it checks the proc flag directly, without extra ELF computation
In addition to making PaX clearer, the combination of these changes fixes
the following bug: if a non-PaX'ed process is launched, and then someone
sets security.pax.{aslr,mprotect,segvguard}.global=1, the process becomes
PaX'ed while its address space hasn't been randomized, which is not likely
to be a good idea.
Now, only the proc flag is checked at runtime, which means the process's
PaX status won't be altered during the execution.
Also:
- declare PAX_DPRINTF, makes it more readable
- fix a typo in exec_elf.h
2015-07-30 18:28:18 +03:00
|
|
|
static bool
|
|
|
|
pax_segvguard_elf_flags_active(uint32_t flags)
|
|
|
|
{
|
|
|
|
if (!pax_segvguard_enabled)
|
|
|
|
return false;
|
|
|
|
if (pax_segvguard_global && (flags & ELF_NOTE_PAX_NOGUARD) != 0) {
|
|
|
|
/* Segvguard explicitly disabled */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!pax_segvguard_global && (flags & ELF_NOTE_PAX_GUARD) == 0) {
|
|
|
|
/* Segvguard not requested */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2006-12-23 11:35:43 +03:00
|
|
|
static void
|
2015-08-04 21:28:09 +03:00
|
|
|
pax_segvguard_cleanup_cb(void *v)
|
2006-11-22 05:02:51 +03:00
|
|
|
{
|
2011-04-24 22:46:22 +04:00
|
|
|
struct pax_segvguard_entry *p = v;
|
2006-11-22 05:02:51 +03:00
|
|
|
struct pax_segvguard_uid_entry *up;
|
|
|
|
|
2011-04-24 22:46:22 +04:00
|
|
|
if (p == NULL) {
|
2006-11-22 05:02:51 +03:00
|
|
|
return;
|
2011-04-24 22:46:22 +04:00
|
|
|
}
|
2006-12-23 11:35:43 +03:00
|
|
|
while ((up = LIST_FIRST(&p->segv_uids)) != NULL) {
|
|
|
|
LIST_REMOVE(up, sue_list);
|
2011-04-24 22:46:22 +04:00
|
|
|
kmem_free(up, sizeof(*up));
|
2006-11-22 05:02:51 +03:00
|
|
|
}
|
2011-04-24 22:46:22 +04:00
|
|
|
kmem_free(p, sizeof(*p));
|
2006-11-22 05:02:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Called when a process of image vp generated a segfault.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
pax_segvguard(struct lwp *l, struct vnode *vp, const char *name,
|
2007-02-22 01:59:35 +03:00
|
|
|
bool crashed)
|
2006-11-22 05:02:51 +03:00
|
|
|
{
|
|
|
|
struct pax_segvguard_entry *p;
|
|
|
|
struct pax_segvguard_uid_entry *up;
|
|
|
|
struct timeval tv;
|
|
|
|
uid_t uid;
|
Revamp PaX:
- don't confuse between ELF flags and proc flags. Introduce the proc-
specific P_PAX_ASLR, P_PAX_MPROTECT and P_PAX_GUARD flags.
- introduce pax_setup_elf_flags(), which takes as argument the PaX flag
of the ELF PaX note section, and which sets the proc flag as
appropriate. Also introduce a couple of other functions used for that
purpose.
- modify pax_aslr_active(), and all the other similar pieces of code, so
that it checks the proc flag directly, without extra ELF computation
In addition to making PaX clearer, the combination of these changes fixes
the following bug: if a non-PaX'ed process is launched, and then someone
sets security.pax.{aslr,mprotect,segvguard}.global=1, the process becomes
PaX'ed while its address space hasn't been randomized, which is not likely
to be a good idea.
Now, only the proc flag is checked at runtime, which means the process's
PaX status won't be altered during the execution.
Also:
- declare PAX_DPRINTF, makes it more readable
- fix a typo in exec_elf.h
2015-07-30 18:28:18 +03:00
|
|
|
uint32_t flags;
|
2007-02-22 01:59:35 +03:00
|
|
|
bool have_uid;
|
2006-11-22 05:02:51 +03:00
|
|
|
|
Revamp PaX:
- don't confuse between ELF flags and proc flags. Introduce the proc-
specific P_PAX_ASLR, P_PAX_MPROTECT and P_PAX_GUARD flags.
- introduce pax_setup_elf_flags(), which takes as argument the PaX flag
of the ELF PaX note section, and which sets the proc flag as
appropriate. Also introduce a couple of other functions used for that
purpose.
- modify pax_aslr_active(), and all the other similar pieces of code, so
that it checks the proc flag directly, without extra ELF computation
In addition to making PaX clearer, the combination of these changes fixes
the following bug: if a non-PaX'ed process is launched, and then someone
sets security.pax.{aslr,mprotect,segvguard}.global=1, the process becomes
PaX'ed while its address space hasn't been randomized, which is not likely
to be a good idea.
Now, only the proc flag is checked at runtime, which means the process's
PaX status won't be altered during the execution.
Also:
- declare PAX_DPRINTF, makes it more readable
- fix a typo in exec_elf.h
2015-07-30 18:28:18 +03:00
|
|
|
flags = l->l_proc->p_pax;
|
2015-08-04 21:28:09 +03:00
|
|
|
if (!pax_flags_active(flags, P_PAX_GUARD))
|
Revamp PaX:
- don't confuse between ELF flags and proc flags. Introduce the proc-
specific P_PAX_ASLR, P_PAX_MPROTECT and P_PAX_GUARD flags.
- introduce pax_setup_elf_flags(), which takes as argument the PaX flag
of the ELF PaX note section, and which sets the proc flag as
appropriate. Also introduce a couple of other functions used for that
purpose.
- modify pax_aslr_active(), and all the other similar pieces of code, so
that it checks the proc flag directly, without extra ELF computation
In addition to making PaX clearer, the combination of these changes fixes
the following bug: if a non-PaX'ed process is launched, and then someone
sets security.pax.{aslr,mprotect,segvguard}.global=1, the process becomes
PaX'ed while its address space hasn't been randomized, which is not likely
to be a good idea.
Now, only the proc flag is checked at runtime, which means the process's
PaX status won't be altered during the execution.
Also:
- declare PAX_DPRINTF, makes it more readable
- fix a typo in exec_elf.h
2015-07-30 18:28:18 +03:00
|
|
|
return 0;
|
2006-11-22 05:02:51 +03:00
|
|
|
|
2006-12-11 18:24:27 +03:00
|
|
|
if (vp == NULL)
|
2015-08-04 21:28:09 +03:00
|
|
|
return EFAULT;
|
2006-11-22 05:02:51 +03:00
|
|
|
|
|
|
|
/* Check if we already monitor the file. */
|
|
|
|
p = fileassoc_lookup(vp, segvguard_id);
|
|
|
|
|
|
|
|
/* Fast-path if starting a program we don't know. */
|
|
|
|
if (p == NULL && !crashed)
|
2015-08-04 21:28:09 +03:00
|
|
|
return 0;
|
2006-11-22 05:02:51 +03:00
|
|
|
|
|
|
|
microtime(&tv);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If a program we don't know crashed, we need to create a new entry
|
|
|
|
* for it.
|
|
|
|
*/
|
|
|
|
if (p == NULL) {
|
2011-04-24 22:46:22 +04:00
|
|
|
p = kmem_alloc(sizeof(*p), KM_SLEEP);
|
2007-02-06 04:09:48 +03:00
|
|
|
fileassoc_add(vp, segvguard_id, p);
|
2006-11-22 05:02:51 +03:00
|
|
|
LIST_INIT(&p->segv_uids);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize a new entry with "crashes so far" of 1.
|
|
|
|
* The expiry time is when we purge the entry if it didn't
|
|
|
|
* reach the limit.
|
|
|
|
*/
|
2011-04-24 22:46:22 +04:00
|
|
|
up = kmem_alloc(sizeof(*up), KM_SLEEP);
|
2006-11-22 05:02:51 +03:00
|
|
|
up->sue_uid = kauth_cred_getuid(l->l_cred);
|
|
|
|
up->sue_ncrashes = 1;
|
|
|
|
up->sue_expiry = tv.tv_sec + pax_segvguard_expiry;
|
|
|
|
up->sue_suspended = 0;
|
|
|
|
LIST_INSERT_HEAD(&p->segv_uids, up, sue_list);
|
2015-08-04 21:28:09 +03:00
|
|
|
return 0;
|
2006-11-22 05:02:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A program we "know" either executed or crashed again.
|
|
|
|
* See if it's a culprit we're familiar with.
|
|
|
|
*/
|
|
|
|
uid = kauth_cred_getuid(l->l_cred);
|
2007-02-22 09:34:42 +03:00
|
|
|
have_uid = false;
|
2006-11-22 05:02:51 +03:00
|
|
|
LIST_FOREACH(up, &p->segv_uids, sue_list) {
|
|
|
|
if (up->sue_uid == uid) {
|
2007-02-22 09:34:42 +03:00
|
|
|
have_uid = true;
|
2006-11-22 05:02:51 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* It's someone else. Add an entry for him if we crashed.
|
|
|
|
*/
|
|
|
|
if (!have_uid) {
|
|
|
|
if (crashed) {
|
2011-04-24 22:46:22 +04:00
|
|
|
up = kmem_alloc(sizeof(*up), KM_SLEEP);
|
2006-11-22 05:02:51 +03:00
|
|
|
up->sue_uid = uid;
|
|
|
|
up->sue_ncrashes = 1;
|
|
|
|
up->sue_expiry = tv.tv_sec + pax_segvguard_expiry;
|
|
|
|
up->sue_suspended = 0;
|
|
|
|
LIST_INSERT_HEAD(&p->segv_uids, up, sue_list);
|
|
|
|
}
|
2015-08-04 21:28:09 +03:00
|
|
|
return 0;
|
2006-11-22 05:02:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (crashed) {
|
|
|
|
/* Check if timer on previous crashes expired first. */
|
|
|
|
if (up->sue_expiry < tv.tv_sec) {
|
|
|
|
log(LOG_INFO, "PaX Segvguard: [%s] Suspension"
|
|
|
|
" expired.\n", name ? name : "unknown");
|
|
|
|
up->sue_ncrashes = 1;
|
|
|
|
up->sue_expiry = tv.tv_sec + pax_segvguard_expiry;
|
|
|
|
up->sue_suspended = 0;
|
2015-08-04 21:28:09 +03:00
|
|
|
return 0;
|
2006-11-22 05:02:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
up->sue_ncrashes++;
|
|
|
|
|
|
|
|
if (up->sue_ncrashes >= pax_segvguard_maxcrashes) {
|
|
|
|
log(LOG_ALERT, "PaX Segvguard: [%s] Suspending "
|
|
|
|
"execution for %d seconds after %zu crashes.\n",
|
|
|
|
name ? name : "unknown", pax_segvguard_suspension,
|
|
|
|
up->sue_ncrashes);
|
|
|
|
|
|
|
|
/* Suspend this program for a while. */
|
|
|
|
up->sue_suspended = tv.tv_sec + pax_segvguard_suspension;
|
|
|
|
up->sue_ncrashes = 0;
|
|
|
|
up->sue_expiry = 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Are we supposed to be suspended? */
|
|
|
|
if (up->sue_suspended > tv.tv_sec) {
|
|
|
|
log(LOG_ALERT, "PaX Segvguard: [%s] Preventing "
|
|
|
|
"execution due to repeated segfaults.\n", name ?
|
|
|
|
name : "unknown");
|
2015-08-04 21:28:09 +03:00
|
|
|
return EPERM;
|
2006-11-22 05:02:51 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-04 21:28:09 +03:00
|
|
|
return 0;
|
2006-11-22 05:02:51 +03:00
|
|
|
}
|
|
|
|
#endif /* PAX_SEGVGUARD */
|