diff options
author | dillon <dillon@FreeBSD.org> | 2000-02-16 21:11:33 +0000 |
---|---|---|
committer | dillon <dillon@FreeBSD.org> | 2000-02-16 21:11:33 +0000 |
commit | 7a2987cf9410d129917e89db27af78911bd0fb60 (patch) | |
tree | e9fa93a9df696f57e919e1e8f97b841d07227b0b /sys/vm/vm_mmap.c | |
parent | e8cfdc976f1f31ae86f30a656797e2820c9f439b (diff) | |
download | FreeBSD-src-7a2987cf9410d129917e89db27af78911bd0fb60.zip FreeBSD-src-7a2987cf9410d129917e89db27af78911bd0fb60.tar.gz |
Fix null-pointer dereference crash when the system is intentionally
run out of KVM through a mmap()/fork() bomb that allocates hundreds
of thousands of vm_map_entry structures.
Add panic to make null-pointer dereference crash a little more verbose.
Add a new sysctl, vm.max_proc_mmap, which specifies the maximum number
of mmap()'d spaces (discrete vm_map_entry's in the process). The value
defaults to around 9000 for a 128MB machine. The test is scaled for the
number of processes sharing a vmspace (aka linux threads). Setting
the value to 0 disables the feature.
PR: kern/16573
Approved by: jkh
Diffstat (limited to 'sys/vm/vm_mmap.c')
-rw-r--r-- | sys/vm/vm_mmap.c | 46 |
1 files changed, 42 insertions, 4 deletions
diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c index bb106f3..b42239c 100644 --- a/sys/vm/vm_mmap.c +++ b/sys/vm/vm_mmap.c @@ -49,6 +49,7 @@ #include "opt_rlimit.h" #include <sys/param.h> +#include <sys/kernel.h> #include <sys/systm.h> #include <sys/sysproto.h> #include <sys/filedesc.h> @@ -60,6 +61,7 @@ #include <sys/conf.h> #include <sys/stat.h> #include <sys/vmmeter.h> +#include <sys/sysctl.h> #include <vm/vm.h> #include <vm/vm_param.h> @@ -72,6 +74,7 @@ #include <vm/vm_pageout.h> #include <vm/vm_extern.h> #include <vm/vm_page.h> +#include <vm/vm_kern.h> #ifndef _SYS_SYSPROTO_H_ struct sbrk_args { @@ -79,6 +82,29 @@ struct sbrk_args { }; #endif +static int max_proc_mmap; +SYSCTL_INT(_vm, OID_AUTO, max_proc_mmap, CTLFLAG_RW, &max_proc_mmap, 0, ""); + +/* + * Set the maximum number of vm_map_entry structures per process. Roughly + * speaking vm_map_entry structures are tiny, so allowing them to eat 1/100 + * of our KVM malloc space still results in generous limits. We want a + * default that is good enough to prevent the kernel running out of resources + * if attacked from compromised user account but generous enough such that + * multi-threaded processes are not unduly inconvenienced. + */ + +static void vmmapentry_rsrc_init __P((void *)); +SYSINIT(vmmersrc, SI_SUB_KVM_RSRC, SI_ORDER_FIRST, vmmapentry_rsrc_init, NULL) + +static void +vmmapentry_rsrc_init(dummy) + void *dummy; +{ + max_proc_mmap = vm_kmem_size / sizeof(struct vm_map_entry); + max_proc_mmap /= 100; +} + /* ARGSUSED */ int sbrk(p, uap) @@ -171,6 +197,7 @@ mmap(p, uap) int flags, error; int disablexworkaround; off_t pos; + struct vmspace *vms = p->p_vmspace; addr = (vm_offset_t) uap->addr; size = uap->len; @@ -234,9 +261,9 @@ mmap(p, uap) * location. */ else if (addr == 0 || - (addr >= round_page((vm_offset_t)p->p_vmspace->vm_taddr) && - addr < round_page((vm_offset_t)p->p_vmspace->vm_daddr + MAXDSIZ))) - addr = round_page((vm_offset_t)p->p_vmspace->vm_daddr + MAXDSIZ); + (addr >= round_page((vm_offset_t)vms->vm_taddr) && + addr < round_page((vm_offset_t)vms->vm_daddr + MAXDSIZ))) + addr = round_page((vm_offset_t)vms->vm_daddr + MAXDSIZ); if (flags & MAP_ANON) { /* @@ -332,7 +359,18 @@ mmap(p, uap) handle = (void *)vp; } } - error = vm_mmap(&p->p_vmspace->vm_map, &addr, size, prot, maxprot, + + /* + * Do not allow more then a certain number of vm_map_entry structures + * per process. Scale with the number of rforks sharing the map + * to make the limit reasonable for threads. + */ + if (max_proc_mmap && + vms->vm_map.nentries >= max_proc_mmap * vms->vm_refcnt) { + return (ENOMEM); + } + + error = vm_mmap(&vms->vm_map, &addr, size, prot, maxprot, flags, handle, pos); if (error == 0) p->p_retval[0] = (register_t) (addr + pageoff); |