summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorelad <elad@NetBSD.org>2006-11-22 02:02:51 +0000
committerelad <elad@NetBSD.org>2006-11-22 02:02:51 +0000
commita84fee7faffe0455d7a4d4f03c03d697bde6849c (patch)
treea598a3231359a9c3ccc229b5b9c2aa9f340660fa
parent25e0bf9073a7cb7cb3443ad5b3b97717c19b18ac (diff)
Initial implementation of PaX Segvguard (this is still work-in-progress,
it's just to get it out of my local tree).
-rw-r--r--lib/libc/gen/sysctl.335
-rw-r--r--sbin/sysctl/sysctl.89
-rw-r--r--share/man/man4/options.427
-rw-r--r--share/man/man8/security.873
-rw-r--r--sys/conf/files5
-rw-r--r--sys/kern/exec_elf32.c13
-rw-r--r--sys/kern/init_main.c13
-rw-r--r--sys/kern/kern_exec.c15
-rw-r--r--sys/kern/kern_pax.c263
-rw-r--r--sys/kern/kern_sig.c12
-rw-r--r--sys/sys/pax.h5
-rw-r--r--usr.bin/paxctl/paxctl.110
-rw-r--r--usr.bin/paxctl/paxctl.c12
13 files changed, 450 insertions, 42 deletions
diff --git a/lib/libc/gen/sysctl.3 b/lib/libc/gen/sysctl.3
index b157ee1f397..3f67bcb7b57 100644
--- a/lib/libc/gen/sysctl.3
+++ b/lib/libc/gen/sysctl.3
@@ -1,4 +1,4 @@
-.\" $NetBSD: sysctl.3,v 1.187 2006/10/19 11:48:02 yamt Exp $
+.\" $NetBSD: sysctl.3,v 1.188 2006/11/22 02:02:52 elad Exp $
.\"
.\" Copyright (c) 1993
.\" The Regents of the University of California. All rights reserved.
@@ -29,7 +29,7 @@
.\"
.\" @(#)sysctl.3 8.4 (Berkeley) 5/9/95
.\"
-.Dd October 19, 2006
+.Dd November 22, 2006
.Dt SYSCTL 3
.Os
.Sh NAME
@@ -2102,8 +2102,7 @@ These are
.Xr mprotect 2
restrictions to better enforce a W^X policy. The value of this
knob must be non-zero for PaX MPROTECT to be enabled, even if a
-process is already marked with
-.Em P_PAXMPROTECT .
+program is set to explicit enable.
.It Li security.pax.mprotect.global
Specifies the default global policy for programs without an
explicit enable/disable flag.
@@ -2114,6 +2113,34 @@ except those exempted with
Otherwise, all programs will not get the PaX MPROTECT restrictions,
except those specifically marked as such with
.Xr paxctl 1 .
+.It Li security.pax.segvguard.enable
+Enable PaX Segvguard.
+.Pp
+Please see
+.Xr security 8
+for more information.
+.Pp
+PaX Segvguard can detect and prevent certain exploitation attempts, where
+an attacker may try for example to brute-force function return addresses
+of respawning daemons.
+.It Li security.pax.segvguard.global
+Specifies the default global policy for programs without an
+explicit enable/disable flag.
+.Pp
+When non-zero, all programs will get the PaX Segvguard,
+except those exempted with
+.Xr paxctl 1 .
+Otherwise, all programs will not get the PaX Segvguard restrictions,
+except those specifically marked as such with
+.Xr paxctl 1 .
+.It Li security.pax.segvguard.expiry_timeout
+If the max number was not reached within this timeout (in seconds), the entry
+will expire.
+.It Li security.pax.segvguard.suspend_timeout
+Number of seconds to suspend a user from running a faulting program when the
+limit was exceeded.
+.It Li security.pax.segvguard.max_crashes
+Max number of segfaults a program can receive before suspension.
.El
.El
.Sh CTL_VENDOR
diff --git a/sbin/sysctl/sysctl.8 b/sbin/sysctl/sysctl.8
index 0b2bc2a4d58..d43c472546d 100644
--- a/sbin/sysctl/sysctl.8
+++ b/sbin/sysctl/sysctl.8
@@ -1,4 +1,4 @@
-.\" $NetBSD: sysctl.8,v 1.154 2006/09/26 14:48:40 elad Exp $
+.\" $NetBSD: sysctl.8,v 1.155 2006/11/22 02:02:52 elad Exp $
.\"
.\" Copyright (c) 2004 The NetBSD Foundation, Inc.
.\" All rights reserved.
@@ -61,7 +61,7 @@
.\"
.\" @(#)sysctl.8 8.1 (Berkeley) 6/6/93
.\"
-.Dd September 26, 2006
+.Dd November 22, 2006
.Dt SYSCTL 8
.Os
.Sh NAME
@@ -555,6 +555,11 @@ privilege can change the value.
.It security.curtain integer yes
.It security.pax.mprotect.enabled integer yes
.It security.pax.mprotect.global integer yes
+.It security.pax.segvguard.enabled integer yes
+.It security.pax.segvguard.global integer yes
+.It security.pax.segvguard.expiry_timeout integer yes
+.It security.pax.segvguard.suspend_timeout integer yes
+.It security.pax.segvguard.max_crashes integer yes
.It user.bc_base_max integer no
.It user.bc_dim_max integer no
.It user.bc_scale_max integer no
diff --git a/share/man/man4/options.4 b/share/man/man4/options.4
index 55541387cdc..b02dcde57b7 100644
--- a/share/man/man4/options.4
+++ b/share/man/man4/options.4
@@ -1,4 +1,4 @@
-.\" $NetBSD: options.4,v 1.339 2006/10/25 13:58:02 jmmv Exp $
+.\" $NetBSD: options.4,v 1.340 2006/11/22 02:02:51 elad Exp $
.\"
.\" Copyright (c) 1996
.\" Perry E. Metzger. All rights reserved.
@@ -30,7 +30,7 @@
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\"
-.Dd October 25, 2006
+.Dd November 22, 2006
.Os
.Dt OPTIONS 4
.Sh NAME
@@ -2224,6 +2224,29 @@ using
If 1, PaX MPROTECT will be enabled to all programs, and exemption can
be done using
.Xr paxctl 1 .
+.Pp
+See
+.Xr security 8
+for more details.
+.It Cd options PAX_SEGVGUARD=value
+Enables PaX Segvguard.
+.Pp
+The
+.Ar value
+is the default value for the
+.Em global
+knob, see
+.Xr sysctl 3 .
+If 0, PaX Segvguard will be enabled only if explicitly set on programs
+using
+.Xr paxctl 1 .
+If 1, PaX Segvguard will be enabled to all programs, and exemption can
+be done using
+.Xr paxctl 1 .
+.Pp
+See
+.Xr security 8
+for more details.
.El
.Ss amiga-specific Options
.Bl -ohang
diff --git a/share/man/man8/security.8 b/share/man/man8/security.8
index 607138525e2..be8a87a5a46 100644
--- a/share/man/man8/security.8
+++ b/share/man/man8/security.8
@@ -1,4 +1,4 @@
-.\" $NetBSD: security.8,v 1.4 2006/10/31 02:06:30 elad Exp $
+.\" $NetBSD: security.8,v 1.5 2006/11/22 02:02:52 elad Exp $
.\"
.\" Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
.\" All rights reserved.
@@ -28,7 +28,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd October 31, 2006
+.Dd November 22, 2006
.Dt SECURITY 8
.Os
.Sh NAME
@@ -91,9 +91,9 @@ also requires enabling in
veriexec=YES
veriexec_strict=1 # IDS mode
.Ed
-.Sh EXPLOITATION MITIGATION
+.Sh EXPLOIT MITIGATION
.Nx
-incorporates some anti-exploitation features, mainly from the
+incorporates some exploit mitigation features, mainly from the
.Em PaX
project.
.Ss PaX MPROTECT
@@ -124,6 +124,61 @@ globally:
.Bd -literal -offset indent
# sysctl -w security.pax.mprotect.global=1
.Ed
+.Ss PaX Segvguard
+.Em PaX Segvguard
+monitors the number of segfaults in a program per-user, in an attempt to
+detect on-going exploitation attempts and possibly prevent them.
+One common attack
+.Em PaX Segvguard
+can help mitigate is when an attacker tries to brute-force a function
+return address, when wanting to perform a return-to-lib attack.
+.Pp
+.Em PaX Segvguard
+makes use of kernel memory, so use it wisely.
+While it provides rate-limiting protections, it works on a per-program
+basis for keeping its records, meaning that irresponsible use may result
+in keeping track of all segfaults in the system, easily wasting all kernel
+memory.
+.Pp
+For this reason, it is highly recommended to have
+.Em PaX Segvguard
+enabled explicitly only for network services etc.
+Enabling
+.Em PaX Segvguard
+explicitly works like this:
+.Bd -literal -offset indent
+# paxctl +G /usr/sbin/sshd
+.Ed
+.Pp
+However, a global knob is still provided, for use in strict environments
+with no local users (some network appliances, embedded devices, firewalls,
+etc.):
+.Bd -literal -offset indent
+# sysctl -w security.pax.segvguard.global=1
+.Ed
+.Pp
+.Em PaX Segvguard
+can be configured to work in your preferred way.
+For example, watching for 5 segfaults from the same user in a time-frame of
+60 seconds:
+.Bd -literal -offset indent
+# sysctl -w security.pax.segvguard.max_crashes=5
+# sysctl -w security.pax.segvguard.expiry_timeout=60
+.Ed
+.Pp
+The number of seconds a user will be suspended from running the culprit
+program is also configurable.
+For example, 10 minutes seem like a sane setting:
+.Bd -literal -offset indent
+# sysctl -w security.pax.segvguard.suspend_timeout=600
+.Ed
+.Pp
+Explicitly disabling
+.Em PaX Segvguard
+can be done like this:
+.Bd -literal -offset indent
+# paxctl +g /bin/ls
+.Ed
.Ss GCC Stack Smashing Protection (SSP)
Since
.Nx 4.0 ,
@@ -143,6 +198,16 @@ or
.Fl fstack-protector-all
flags to
.Xr gcc 1 .
+.Pp
+The system (userland, kernel) can be built with
+.Em SSP
+by using the
+.Dq USE_SSP
+flag in
+.Pa /etc/mk.conf:
+.Bd -literal -offset indent
+USE_SSP=yes
+.Ed
.Sh INFORMATION FILTERING
.Nx
provides administrators with the ability to restrict information passed from
diff --git a/sys/conf/files b/sys/conf/files
index 82f1d23e0c5..fad506448ab 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1,4 +1,4 @@
-# $NetBSD: files,v 1.816 2006/10/27 21:20:48 christos Exp $
+# $NetBSD: files,v 1.817 2006/11/22 02:02:51 elad Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@@ -90,6 +90,7 @@ defflag opt_syscall_stats.h SYSCALL_TIMES_HASCOUNTER: SYSCALL_TIMES
file kern/subr_syscall_stats.c syscall_stats
defparam opt_pax.h PAX_MPROTECT
+ PAX_SEGVGUARD
defflag opt_fileassoc.h FILEASSOC
defparam opt_fileassoc.h FILEASSOC_NHOOKS
@@ -1289,7 +1290,7 @@ file kern/kern_malloc.c
file kern/kern_malloc_debug.c malloc_debug
file kern/kern_fileassoc.c fileassoc
file kern/kern_ntptime.c
-file kern/kern_pax.c pax_mprotect
+file kern/kern_pax.c pax_mprotect | pax_segvguard
file kern/kern_physio.c
file kern/kern_proc.c
file kern/kern_prot.c
diff --git a/sys/kern/exec_elf32.c b/sys/kern/exec_elf32.c
index b7aa4f2a9c0..00aac776a56 100644
--- a/sys/kern/exec_elf32.c
+++ b/sys/kern/exec_elf32.c
@@ -1,4 +1,4 @@
-/* $NetBSD: exec_elf32.c,v 1.118 2006/11/22 00:41:38 elad Exp $ */
+/* $NetBSD: exec_elf32.c,v 1.119 2006/11/22 02:02:51 elad Exp $ */
/*-
* Copyright (c) 1994, 2000, 2005 The NetBSD Foundation, Inc.
@@ -64,7 +64,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: exec_elf32.c,v 1.118 2006/11/22 00:41:38 elad Exp $");
+__KERNEL_RCSID(1, "$NetBSD: exec_elf32.c,v 1.119 2006/11/22 02:02:51 elad Exp $");
/* If not included by exec_elf64.c, ELFSIZE won't be defined. */
#ifndef ELFSIZE
@@ -91,9 +91,9 @@ __KERNEL_RCSID(1, "$NetBSD: exec_elf32.c,v 1.118 2006/11/22 00:41:38 elad Exp $"
#include <machine/cpu.h>
#include <machine/reg.h>
-#if defined(PAX_MPROTECT)
+#if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD)
#include <sys/pax.h>
-#endif /* PAX_MPROTECT */
+#endif /* PAX_MPROTECT || PAX_SEGVGUARD */
extern const struct emul emul_netbsd;
@@ -690,11 +690,10 @@ exec_elf_makecmds(struct lwp *l, struct exec_package *epp)
case PT_INTERP:
/* Already did this one. */
case PT_DYNAMIC:
- break;
case PT_NOTE:
-#if defined(PAX_MPROTECT)
+#if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD)
pax_adjust(l, ph[i].p_flags);
-#endif /* PAX_MPROTECT */
+#endif /* PAX_MPROTECT || PAX_SEGVGUARD */
break;
case PT_PHDR:
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
index 626176b9bd7..18520e09382 100644
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -1,4 +1,4 @@
-/* $NetBSD: init_main.c,v 1.281 2006/11/22 00:41:38 elad Exp $ */
+/* $NetBSD: init_main.c,v 1.282 2006/11/22 02:02:51 elad Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1991, 1992, 1993
@@ -71,7 +71,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.281 2006/11/22 00:41:38 elad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.282 2006/11/22 02:02:51 elad Exp $");
#include "opt_ipsec.h"
#include "opt_kcont.h"
@@ -156,10 +156,9 @@ __KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.281 2006/11/22 00:41:38 elad Exp $")
#include <sys/fileassoc.h>
#endif /* FILEASSOC */
-#if defined(PAX_MPROTECT)
+#if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD)
#include <sys/pax.h>
-#endif /* PAX_MPROTECT */
-
+#endif /* PAX_MPROTECT || PAX_SEGVGUARD */
#include <ufs/ufs/quota.h>
#include <miscfs/genfs/genfs.h>
@@ -390,9 +389,9 @@ main(void)
veriexec_init_fp_ops();
#endif /* NVERIEXEC > 0 */
-#if defined(PAX_MPROTECT)
+#if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD)
pax_init();
-#endif /* PAX_MPROTECT */
+#endif /* PAX_MPROTECT || PAX_SEGVGUARD */
/* Attach pseudo-devices. */
for (pdev = pdevinit; pdev->pdev_attach != NULL; pdev++)
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index b951f00b08e..7135d535727 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_exec.c,v 1.231 2006/11/01 10:17:58 yamt Exp $ */
+/* $NetBSD: kern_exec.c,v 1.232 2006/11/22 02:02:51 elad Exp $ */
/*-
* Copyright (C) 1993, 1994, 1996 Christopher G. Demetriou
@@ -33,12 +33,13 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.231 2006/11/01 10:17:58 yamt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.232 2006/11/22 02:02:51 elad Exp $");
#include "opt_ktrace.h"
#include "opt_syscall_debug.h"
#include "opt_compat_netbsd.h"
#include "veriexec.h"
+#include "opt_pax.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -73,6 +74,10 @@ __KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.231 2006/11/01 10:17:58 yamt Exp $")
#include <sys/systrace.h>
#endif /* SYSTRACE */
+#ifdef PAX_SEGVGUARD
+#include <sys/pax.h>
+#endif /* PAX_SEGVGUARD */
+
#include <uvm/uvm_extern.h>
#include <machine/cpu.h>
@@ -282,13 +287,17 @@ check_exec(struct lwp *l, struct exec_package *epp, int flag)
/* unlock vp, since we need it unlocked from here on out. */
VOP_UNLOCK(vp, 0);
-
#if NVERIEXEC > 0
if ((error = veriexec_verify(l, vp, epp->ep_ndp->ni_dirp, flag,
NULL)) != 0)
goto bad2;
#endif /* NVERIEXEC > 0 */
+#ifdef PAX_SEGVGUARD
+ if (pax_segvguard(l, vp, epp->ep_ndp->ni_dirp, FALSE))
+ return (EPERM);
+#endif /* PAX_SEGVGUARD */
+
/* now we have the file, get the exec header */
uvn_attach(vp, VM_PROT_READ);
error = vn_rdwr(UIO_READ, vp, epp->ep_hdr, epp->ep_hdrlen, 0,
diff --git a/sys/kern/kern_pax.c b/sys/kern/kern_pax.c
index 5087fc5c27f..8d55004e100 100644
--- a/sys/kern/kern_pax.c
+++ b/sys/kern/kern_pax.c
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_pax.c,v 1.7 2006/11/22 00:41:38 elad Exp $ */
+/* $NetBSD: kern_pax.c,v 1.8 2006/11/22 02:02:51 elad Exp $ */
/*-
* Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
@@ -37,21 +37,64 @@
#include <sys/exec_elf.h>
#include <sys/pax.h>
#include <sys/sysctl.h>
+#include <sys/malloc.h>
+#include <sys/fileassoc.h>
+#include <sys/syslog.h>
+#include <sys/vnode.h>
+#include <sys/queue.h>
+#include <sys/kauth.h>
#ifdef PAX_MPROTECT
static int pax_mprotect_enabled = 1;
static int pax_mprotect_global = PAX_MPROTECT;
specificdata_key_t pax_mprotect_key;
-#endif /* PAX_MPROTECT */
+#endif
+
+#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
+
+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;
+specificdata_key_t pax_segvguard_key;
+
+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;
+};
+#endif /* PAX_SEGVGUARD */
/* PaX internal setspecific flags */
#define PAX_MPROTECT_EXPLICIT_ENABLE (void *)0x01
#define PAX_MPROTECT_EXPLICIT_DISABLE (void *)0x02
+#define PAX_SEGVGUARD_EXPLICIT_ENABLE (void *)0x03
+#define PAX_SEGVGUARD_EXPLICIT_DISABLE (void *)0x04
SYSCTL_SETUP(sysctl_security_pax_setup, "sysctl security.pax setup")
{
- const struct sysctlnode *rnode = NULL;
+ const struct sysctlnode *rnode = NULL, *cnode;
sysctl_createv(clog, 0, NULL, &rnode,
CTLFLAG_PERMANENT,
@@ -66,6 +109,8 @@ SYSCTL_SETUP(sysctl_security_pax_setup, "sysctl security.pax setup")
NULL, 0, NULL, 0,
CTL_CREATE, CTL_EOL);
+ cnode = rnode;
+
#ifdef PAX_MPROTECT
sysctl_createv(clog, 0, &rnode, &rnode,
CTLFLAG_PERMANENT,
@@ -88,6 +133,47 @@ SYSCTL_SETUP(sysctl_security_pax_setup, "sysctl security.pax setup")
NULL, 0, &pax_mprotect_global, 0,
CTL_CREATE, CTL_EOL);
#endif /* PAX_MPROTECT */
+
+ rnode = cnode;
+
+#ifdef PAX_SEGVGUARD
+ 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 */
}
/*
@@ -99,6 +185,11 @@ pax_init(void)
#ifdef PAX_MPROTECT
proc_specific_key_create(&pax_mprotect_key, NULL);
#endif /* PAX_MPROTECT */
+
+#ifdef PAX_SEGVGUARD
+ segvguard_id = fileassoc_register("segvguard", pax_segvguard_cb);
+ proc_specific_key_create(&pax_segvguard_key, NULL);
+#endif /* PAX_SEGVGUARD */
}
void
@@ -114,6 +205,18 @@ pax_adjust(struct lwp *l, int f)
PAX_MPROTECT_EXPLICIT_DISABLE);
}
#endif /* PAX_MPROTECT */
+
+#ifdef PAX_SEGVGUARD
+ if (pax_segvguard_enabled) {
+ if (f & PF_PAXGUARD) {
+ proc_setspecific(l->l_proc, pax_segvguard_key,
+ PAX_SEGVGUARD_EXPLICIT_ENABLE);
+ }
+ if (f & PF_PAXNOGUARD)
+ proc_setspecific(l->l_proc, pax_segvguard_key,
+ PAX_SEGVGUARD_EXPLICIT_DISABLE);
+ }
+#endif /* PAX_SEGVGUARD */
}
#ifdef PAX_MPROTECT
@@ -139,3 +242,157 @@ pax_mprotect(struct lwp *l, vm_prot_t *prot, vm_prot_t *maxprot)
}
}
#endif /* PAX_MPROTECT */
+
+#ifdef PAX_SEGVGUARD
+void
+pax_segvguard_cb(void *v, int what)
+{
+ struct pax_segvguard_entry *p;
+ struct pax_segvguard_uid_entry *up;
+
+ if (v == NULL)
+ return;
+
+ if (what == FILEASSOC_CLEANUP_FILE) {
+ p = v;
+ while ((up = LIST_FIRST(&p->segv_uids)) != NULL) {
+ LIST_REMOVE(up, sue_list);
+ free(up, M_TEMP);
+ }
+ }
+
+ free(v, M_TEMP);
+}
+
+/*
+ * Called when a process of image vp generated a segfault.
+ */
+int
+pax_segvguard(struct lwp *l, struct vnode *vp, const char *name,
+ boolean_t crashed)
+{
+ struct pax_segvguard_entry *p;
+ struct pax_segvguard_uid_entry *up;
+ struct timeval tv;
+ uid_t uid;
+ void *t;
+ boolean_t have_uid;
+
+ if (!pax_segvguard_enabled)
+ return (0);
+
+ t = proc_getspecific(l->l_proc, pax_segvguard_key);
+ if ((pax_segvguard_global && t == PAX_SEGVGUARD_EXPLICIT_DISABLE) ||
+ (!pax_segvguard_global && t != PAX_SEGVGUARD_EXPLICIT_ENABLE))
+ return (0);
+
+ if (segvguard_id == FILEASSOC_INVAL || vp == NULL)
+ return (EFAULT);
+
+ /* 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)
+ return (0);
+
+ microtime(&tv);
+
+ /*
+ * If a program we don't know crashed, we need to create a new entry
+ * for it.
+ */
+ if (p == NULL) {
+ p = malloc(sizeof(*p), M_TEMP, M_WAITOK);
+ if (fileassoc_add(vp, segvguard_id, p) != 0) {
+ fileassoc_table_add(vp->v_mount, 16);
+ fileassoc_add(vp, segvguard_id, p);
+ }
+ 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.
+ */
+ up = malloc(sizeof(*up), M_TEMP, M_WAITOK);
+ 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);
+
+ return (0);
+ }
+
+ /*
+ * 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);
+ have_uid = FALSE;
+ LIST_FOREACH(up, &p->segv_uids, sue_list) {
+ if (up->sue_uid == uid) {
+ have_uid = TRUE;
+ break;
+ }
+ }
+
+ /*
+ * It's someone else. Add an entry for him if we crashed.
+ */
+ if (!have_uid) {
+ if (crashed) {
+ up = malloc(sizeof(*up), M_TEMP, M_WAITOK);
+ 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);
+ }
+
+ return (0);
+ }
+
+ 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;
+
+ return (0);
+ }
+
+ 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");
+
+ return (EPERM);
+ }
+ }
+
+ return (0);
+}
+#endif /* PAX_SEGVGUARD */
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index dd5e0e75dd2..7648e8dd03e 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_sig.c,v 1.239 2006/11/08 20:18:33 drochner Exp $ */
+/* $NetBSD: kern_sig.c,v 1.240 2006/11/22 02:02:51 elad Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1991, 1993
@@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.239 2006/11/08 20:18:33 drochner Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.240 2006/11/22 02:02:51 elad Exp $");
#include "opt_coredump.h"
#include "opt_ktrace.h"
@@ -46,6 +46,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.239 2006/11/08 20:18:33 drochner Exp
#include "opt_compat_sunos.h"
#include "opt_compat_netbsd.h"
#include "opt_compat_netbsd32.h"
+#include "opt_pax.h"
#define SIGPROP /* include signal properties table */
#include <sys/param.h>
@@ -83,6 +84,10 @@ __KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.239 2006/11/08 20:18:33 drochner Exp
#include <sys/user.h> /* for coredump */
+#ifdef PAX_SEGVGUARD
+#include <sys/pax.h>
+#endif /* PAX_SEGVGUARD */
+
#include <uvm/uvm.h>
#include <uvm/uvm_extern.h>
@@ -2085,6 +2090,9 @@ sigexit(struct lwp *l, int signum)
p->p_comm, uid, signum);
}
+#ifdef PAX_SEGVGUARD
+ pax_segvguard(l, p->p_textvp, p->p_comm, TRUE);
+#endif /* PAX_SEGVGUARD */
}
exit1(l, W_EXITCODE(0, exitsig));
diff --git a/sys/sys/pax.h b/sys/sys/pax.h
index c8bd5952b70..1b27c1f89d1 100644
--- a/sys/sys/pax.h
+++ b/sys/sys/pax.h
@@ -1,4 +1,4 @@
-/* $NetBSD: pax.h,v 1.4 2006/11/22 00:41:38 elad Exp $ */
+/* $NetBSD: pax.h,v 1.5 2006/11/22 02:02:51 elad Exp $ */
/*-
* Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
@@ -42,5 +42,8 @@ void pax_adjust(struct lwp *, int);
void pax_mprotect(struct lwp *, vm_prot_t *, vm_prot_t *);
+int pax_segvguard(struct lwp *, struct vnode *, const char *, boolean_t);
+void pax_segvguard_cb(void *, int);
+
#endif /* !__SYS_PAX_H__ */
diff --git a/usr.bin/paxctl/paxctl.1 b/usr.bin/paxctl/paxctl.1
index 1db2f8d7c68..9acf2ac067d 100644
--- a/usr.bin/paxctl/paxctl.1
+++ b/usr.bin/paxctl/paxctl.1
@@ -1,4 +1,4 @@
-.\" $NetBSD: paxctl.1,v 1.2 2006/10/31 01:27:53 elad Exp $
+.\" $NetBSD: paxctl.1,v 1.3 2006/11/22 02:02:52 elad Exp $
.\"
.\" Copyright 2006 Elad Efrat <elad@NetBSD.org>
.\" All rights reserved.
@@ -25,7 +25,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd October 31, 2006
+.Dd November 22, 2006
.Dt PAXCTL 1
.Os
.Sh NAME
@@ -52,6 +52,12 @@ sign to add or remove the flag, respectively.
.Pp
The following flags are available:
.Bl -tag -width flag
+.It g
+Explicitly disable PaX Segvguard for
+.Ar program .
+.It G
+Explicitly enable PaX Segvguard for
+.Ar program .
.It m
Explicitly disable PaX MPROTECT
.Xr ( mprotect 2
diff --git a/usr.bin/paxctl/paxctl.c b/usr.bin/paxctl/paxctl.c
index 890e6bafdd9..901f5b51276 100644
--- a/usr.bin/paxctl/paxctl.c
+++ b/usr.bin/paxctl/paxctl.c
@@ -1,4 +1,4 @@
-/* $NetBSD: paxctl.c,v 1.8 2006/11/20 16:51:44 elad Exp $ */
+/* $NetBSD: paxctl.c,v 1.9 2006/11/22 02:02:52 elad Exp $ */
/*-
* Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
@@ -36,7 +36,7 @@
#include <sys/cdefs.h>
#ifndef lint
#ifdef __RCSID
-__RCSID("$NetBSD: paxctl.c,v 1.8 2006/11/20 16:51:44 elad Exp $");
+__RCSID("$NetBSD: paxctl.c,v 1.9 2006/11/22 02:02:52 elad Exp $");
#endif
#endif /* not lint */
@@ -59,6 +59,10 @@ static void pax_printflags(u_long);
#define PF_PAXMPROTECT 0x08000000
#define PF_PAXNOMPROTECT 0x04000000
#endif
+#ifndef PF_PAXGUARD
+#define PF_PAXGUARD 0x02000000
+#define PF_PAXNOGUARD 0x01000000
+#endif
#ifndef __arraycount
#define __arraycount(a) (sizeof(a) / sizeof(a[0]))
#endif
@@ -69,6 +73,8 @@ static const struct paxflag {
const char *name;
int bits;
} flags[] = {
+ { 'G', "Segvguard, explicit enable", PF_PAXGUARD },
+ { 'g', "Segvguard, explicit disable", PF_PAXNOGUARD },
{ 'M', "mprotect(2) restrictions, explicit enable", PF_PAXMPROTECT },
{ 'm', "mprotect(2) restrictions, explicit disable", PF_PAXNOMPROTECT },
};
@@ -76,7 +82,7 @@ static const struct paxflag {
static void
usage(void)
{
- (void)fprintf(stderr, "Usage: %s [ <-|+>m | <-|+>M ] <file>\n",
+ (void)fprintf(stderr, "Usage: %s [ <-|+><G|g|M|m> ] <file>\n",
#if HAVE_NBTOOL_CONFIG_H
"paxctl"
#else