Implement a (soft) stack guard page for auto-growing stack mappings.

The unmapped page separates the tip of the stack and possible adjanced
segment, making some uses of stack overflow harder.  The stack growing
code refuses to expand the segment to the last page of the reseved
region when sysctl security.bsd.stack_guard_page is set to 1. The
default value for sysctl and accompanying tunable is 0.

Please note that mmap(MAP_FIXED) still can place a mapping right up to
the stack, making continuous region.

Reviewed by:	alc
MFC after:	1 week
This commit is contained in:
Konstantin Belousov 2010-11-14 17:53:52 +00:00
parent 60db6c3233
commit 9a6d144ff8

View File

@ -67,6 +67,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/lock.h>
#include <sys/mutex.h>
@ -76,6 +77,7 @@ __FBSDID("$FreeBSD$");
#include <sys/vnode.h>
#include <sys/resourcevar.h>
#include <sys/file.h>
#include <sys/sysctl.h>
#include <sys/sysent.h>
#include <sys/shm.h>
@ -3216,6 +3218,12 @@ vm_map_stack(vm_map_t map, vm_offset_t addrbos, vm_size_t max_ssize,
return (rv);
}
static int stack_guard_page = 0;
TUNABLE_INT("security.bsd.stack_guard_page", &stack_guard_page);
SYSCTL_INT(_security_bsd, OID_AUTO, stack_guard_page, CTLFLAG_RW,
&stack_guard_page, 0,
"Insert stack guard page ahead of the growable segments.");
/* Attempts to grow a vm stack entry. Returns KERN_SUCCESS if the
* desired address is already mapped, or if we successfully grow
* the stack. Also returns KERN_SUCCESS if addr is outside the
@ -3312,7 +3320,7 @@ vm_map_growstack(struct proc *p, vm_offset_t addr)
* This also effectively destroys any guard page the user might have
* intended by limiting the stack size.
*/
if (grow_amount > max_grow) {
if (grow_amount + (stack_guard_page ? PAGE_SIZE : 0) > max_grow) {
if (vm_map_lock_upgrade(map))
goto Retry;
@ -3365,6 +3373,8 @@ vm_map_growstack(struct proc *p, vm_offset_t addr)
if (addr < end) {
stack_entry->avail_ssize = max_grow;
addr = end;
if (stack_guard_page)
addr += PAGE_SIZE;
}
rv = vm_map_insert(map, NULL, 0, addr, stack_entry->start,
@ -3397,6 +3407,8 @@ vm_map_growstack(struct proc *p, vm_offset_t addr)
if (addr > end) {
stack_entry->avail_ssize = end - stack_entry->end;
addr = end;
if (stack_guard_page)
addr -= PAGE_SIZE;
}
grow_amount = addr - stack_entry->end;