- The Open Group Base Specifications Issue 6 specifies that an munmap(2)

must return EINVAL if size is zero.  Submitted by: tegge
 - In order to avoid a race condition in multithreaded applications, the
   check and removal operations by munmap(2) must be in the same critical
   section.  To accomodate this, vm_map_check_protection() is modified to
   require its caller to obtain at least a read lock on the map.
This commit is contained in:
Alan Cox 2003-11-10 01:37:40 +00:00
parent 8f101a2f31
commit d88346020b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=122384
3 changed files with 18 additions and 20 deletions

View File

@ -144,7 +144,9 @@ kernacc(addr, len, rw)
prot = rw;
saddr = trunc_page((vm_offset_t)addr);
eaddr = round_page((vm_offset_t)addr + len);
vm_map_lock_read(kernel_map);
rv = vm_map_check_protection(kernel_map, saddr, eaddr, prot);
vm_map_unlock_read(kernel_map);
return (rv == TRUE);
}
@ -174,8 +176,10 @@ useracc(addr, len, rw)
(vm_offset_t)addr + len < (vm_offset_t)addr) {
return (FALSE);
}
vm_map_lock_read(map);
rv = vm_map_check_protection(map, trunc_page((vm_offset_t)addr),
round_page((vm_offset_t)addr + len), prot);
vm_map_unlock_read(map);
return (rv == TRUE);
}

View File

@ -2227,6 +2227,8 @@ vm_map_remove(vm_map_t map, vm_offset_t start, vm_offset_t end)
* might be mapped into a larger address space.
*
* NOTE! This code is also called by munmap().
*
* The map must be locked. A read lock is sufficient.
*/
boolean_t
vm_map_check_protection(vm_map_t map, vm_offset_t start, vm_offset_t end,
@ -2235,37 +2237,27 @@ vm_map_check_protection(vm_map_t map, vm_offset_t start, vm_offset_t end,
vm_map_entry_t entry;
vm_map_entry_t tmp_entry;
vm_map_lock_read(map);
if (!vm_map_lookup_entry(map, start, &tmp_entry)) {
vm_map_unlock_read(map);
if (!vm_map_lookup_entry(map, start, &tmp_entry))
return (FALSE);
}
entry = tmp_entry;
while (start < end) {
if (entry == &map->header) {
vm_map_unlock_read(map);
if (entry == &map->header)
return (FALSE);
}
/*
* No holes allowed!
*/
if (start < entry->start) {
vm_map_unlock_read(map);
if (start < entry->start)
return (FALSE);
}
/*
* Check protection associated with entry.
*/
if ((entry->protection & protection) != protection) {
vm_map_unlock_read(map);
if ((entry->protection & protection) != protection)
return (FALSE);
}
/* go to next entry */
start = entry->end;
entry = entry->next;
}
vm_map_unlock_read(map);
return (TRUE);
}

View File

@ -585,6 +585,8 @@ munmap(td, uap)
addr = (vm_offset_t) uap->addr;
size = uap->len;
if (size == 0)
return (EINVAL);
pageoff = (addr & PAGE_MASK);
addr -= pageoff;
@ -593,23 +595,23 @@ munmap(td, uap)
if (addr + size < addr)
return (EINVAL);
if (size == 0)
return (0);
/*
* Check for illegal addresses. Watch out for address wrap...
*/
map = &td->td_proc->p_vmspace->vm_map;
if (addr < vm_map_min(map) || addr + size > vm_map_max(map))
return (EINVAL);
vm_map_lock(map);
/*
* Make sure entire range is allocated.
*/
if (!vm_map_check_protection(map, addr, addr + size, VM_PROT_NONE))
if (!vm_map_check_protection(map, addr, addr + size, VM_PROT_NONE)) {
vm_map_unlock(map);
return (EINVAL);
}
/* returns nothing but KERN_SUCCESS anyway */
(void) vm_map_remove(map, addr, addr + size);
vm_map_delete(map, addr, addr + size);
vm_map_unlock(map);
return (0);
}