diff options
| -rw-r--r-- | lib/libc/sys/mmap.2 | 3 | ||||
| -rw-r--r-- | sys/kern/kern_malloc.c | 3 | ||||
| -rw-r--r-- | sys/sys/kernel.h | 1 | ||||
| -rw-r--r-- | sys/vm/vm_kern.h | 1 | ||||
| -rw-r--r-- | sys/vm/vm_map.c | 8 | ||||
| -rw-r--r-- | sys/vm/vm_mmap.c | 46 |
6 files changed, 55 insertions, 7 deletions
diff --git a/lib/libc/sys/mmap.2 b/lib/libc/sys/mmap.2 index 1906e534cbcc..433f8b798514 100644 --- a/lib/libc/sys/mmap.2 +++ b/lib/libc/sys/mmap.2 @@ -253,7 +253,8 @@ was not page-aligned. (See BUGS below.) .Dv MAP_FIXED was specified and the .Fa addr -parameter wasn't available. +parameter wasn't available, or the system has reached the per-process mmap +limit specified in the vm.max_proc_mmap sysctl. .Dv MAP_ANON was specified and insufficient memory was available. .Sh "SEE ALSO" diff --git a/sys/kern/kern_malloc.c b/sys/kern/kern_malloc.c index 8852859232a8..8f9da1f99328 100644 --- a/sys/kern/kern_malloc.c +++ b/sys/kern/kern_malloc.c @@ -72,7 +72,8 @@ static struct kmembuckets bucket[MINBUCKET + 16]; static struct kmemusage *kmemusage; static char *kmembase; static char *kmemlimit; -static u_int vm_kmem_size; + +u_int vm_kmem_size; #ifdef INVARIANTS /* diff --git a/sys/sys/kernel.h b/sys/sys/kernel.h index eac0fe7d9d8b..a93de9c97ee1 100644 --- a/sys/sys/kernel.h +++ b/sys/sys/kernel.h @@ -112,6 +112,7 @@ enum sysinit_sub_id { SI_SUB_TUNABLES = 0x0700000, /* establish tunable values */ SI_SUB_VM = 0x1000000, /* virtual memory system init*/ SI_SUB_KMEM = 0x1800000, /* kernel memory*/ + SI_SUB_KVM_RSRC = 0x1A00000, /* kvm operational limits*/ SI_SUB_CPU = 0x2000000, /* CPU resource(s)*/ SI_SUB_KLD = 0x2100000, /* KLD and module setup */ SI_SUB_INTRINSIC = 0x2200000, /* proc 0*/ diff --git a/sys/vm/vm_kern.h b/sys/vm/vm_kern.h index 2f1fe76aae44..a962c1782f53 100644 --- a/sys/vm/vm_kern.h +++ b/sys/vm/vm_kern.h @@ -75,6 +75,7 @@ extern vm_map_t mb_map; extern int mb_map_full; extern vm_map_t clean_map; extern vm_map_t exec_map; +extern u_int vm_kmem_size; extern vm_offset_t kernel_vm_end; /* XXX - elsewhere? */ diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c index 3f5382e1909f..7acaa5118b4d 100644 --- a/sys/vm/vm_map.c +++ b/sys/vm/vm_map.c @@ -284,7 +284,13 @@ static vm_map_entry_t vm_map_entry_create(map) vm_map_t map; { - return zalloc((map->system_map || !mapentzone) ? kmapentzone : mapentzone); + vm_map_entry_t new_entry; + + new_entry = zalloc((map->system_map || !mapentzone) ? + kmapentzone : mapentzone); + if (new_entry == NULL) + panic("vm_map_entry_create: kernel resources exhausted"); + return(new_entry); } /* diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c index bb106f3d0094..b42239cdab87 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); |
