aboutsummaryrefslogtreecommitdiff
path: root/sys/vm/vm_map.c
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2009-10-27 10:15:58 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2009-10-27 10:15:58 +0000
commit210a688642f7e851e453853f45cdc90e016df1ff (patch)
tree3db96f50949e0d11ed042308a247806c6d75a745 /sys/vm/vm_map.c
parent207ec3a836dcb63be61bbbc607a8cda3ffe0206d (diff)
downloadsrc-210a688642f7e851e453853f45cdc90e016df1ff.tar.gz
src-210a688642f7e851e453853f45cdc90e016df1ff.zip
When protection of wired read-only mapping is changed to read-write,
install new shadow object behind the map entry and copy the pages from the underlying objects to it. This makes the mprotect(2) call to actually perform the requested operation instead of silently do nothing and return success, that causes SIGSEGV on later write access to the mapping. Reuse vm_fault_copy_entry() to do the copying, modifying it to behave correctly when src_entry == dst_entry. Reviewed by: alc MFC after: 3 weeks
Notes
Notes: svn path=/head/; revision=198505
Diffstat (limited to 'sys/vm/vm_map.c')
-rw-r--r--sys/vm/vm_map.c14
1 files changed, 10 insertions, 4 deletions
diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c
index 116671294c4b..06ae63e622bd 100644
--- a/sys/vm/vm_map.c
+++ b/sys/vm/vm_map.c
@@ -1805,10 +1805,10 @@ int
vm_map_protect(vm_map_t map, vm_offset_t start, vm_offset_t end,
vm_prot_t new_prot, boolean_t set_max)
{
- vm_map_entry_t current;
- vm_map_entry_t entry;
+ vm_map_entry_t current, entry;
vm_object_t obj;
struct uidinfo *uip;
+ vm_prot_t old_prot;
vm_map_lock(map);
@@ -1897,9 +1897,8 @@ vm_map_protect(vm_map_t map, vm_offset_t start, vm_offset_t end,
*/
current = entry;
while ((current != &map->header) && (current->start < end)) {
- vm_prot_t old_prot;
-
old_prot = current->protection;
+
if (set_max)
current->protection =
(current->max_protection = new_prot) &
@@ -1907,6 +1906,13 @@ vm_map_protect(vm_map_t map, vm_offset_t start, vm_offset_t end,
else
current->protection = new_prot;
+ if ((current->eflags & (MAP_ENTRY_COW | MAP_ENTRY_USER_WIRED))
+ == (MAP_ENTRY_COW | MAP_ENTRY_USER_WIRED) &&
+ (current->protection & VM_PROT_WRITE) != 0 &&
+ (old_prot & VM_PROT_WRITE) == 0) {
+ vm_fault_copy_entry(map, map, current, current, NULL);
+ }
+
/*
* Update physical map if necessary. Worry about copy-on-write
* here.