diff options
| author | elad <elad@NetBSD.org> | 2006-11-22 02:02:51 +0000 |
|---|---|---|
| committer | elad <elad@NetBSD.org> | 2006-11-22 02:02:51 +0000 |
| commit | a84fee7faffe0455d7a4d4f03c03d697bde6849c (patch) | |
| tree | a598a3231359a9c3ccc229b5b9c2aa9f340660fa | |
| parent | 25e0bf9073a7cb7cb3443ad5b3b97717c19b18ac (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.3 | 35 | ||||
| -rw-r--r-- | sbin/sysctl/sysctl.8 | 9 | ||||
| -rw-r--r-- | share/man/man4/options.4 | 27 | ||||
| -rw-r--r-- | share/man/man8/security.8 | 73 | ||||
| -rw-r--r-- | sys/conf/files | 5 | ||||
| -rw-r--r-- | sys/kern/exec_elf32.c | 13 | ||||
| -rw-r--r-- | sys/kern/init_main.c | 13 | ||||
| -rw-r--r-- | sys/kern/kern_exec.c | 15 | ||||
| -rw-r--r-- | sys/kern/kern_pax.c | 263 | ||||
| -rw-r--r-- | sys/kern/kern_sig.c | 12 | ||||
| -rw-r--r-- | sys/sys/pax.h | 5 | ||||
| -rw-r--r-- | usr.bin/paxctl/paxctl.1 | 10 | ||||
| -rw-r--r-- | usr.bin/paxctl/paxctl.c | 12 |
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 |
