--- linux-2.4.22/mm/mremap.c Mon Aug 25 13:44:44 2003 +++ linux-2.4.26/mm/mremap.c Wed Apr 14 15:05:41 2004 @@ -77,12 +77,16 @@ static int move_one_page(struct mm_struct *mm, unsigned long old_addr, unsigned long new_addr) { int error = 0; - pte_t * src; + pte_t * src, * dst; spin_lock(&mm->page_table_lock); src = get_one_pte(mm, old_addr); - if (src) - error = copy_one_pte(mm, src, alloc_one_pte(mm, new_addr)); + if (src) { + dst = alloc_one_pte(mm, new_addr); + src = get_one_pte(mm, old_addr); + if (src) + error = copy_one_pte(mm, src, dst); + } spin_unlock(&mm->page_table_lock); return error; } @@ -241,6 +245,13 @@ if (new_len > TASK_SIZE || new_addr > TASK_SIZE - new_len) goto out; + /* + * Allow new_len == 0 only if new_addr == addr + * to preserve truncation in place (that was working + * safe and some app may depend on it). + */ + if (unlikely(!new_len && new_addr != addr)) + goto out; /* Check if the location we're moving into overlaps the * old location at all, and fail if it does. @@ -251,16 +262,20 @@ if ((addr <= new_addr) && (addr+old_len) > new_addr) goto out; - do_munmap(current->mm, new_addr, new_len); + ret = do_munmap(current->mm, new_addr, new_len); + if (ret && new_len) + goto out; } /* * Always allow a shrinking remap: that just unmaps * the unnecessary pages.. */ - ret = addr; if (old_len >= new_len) { - do_munmap(current->mm, addr+new_len, old_len - new_len); + ret = do_munmap(current->mm, addr+new_len, old_len - new_len); + if (ret && old_len != new_len) + goto out; + ret = addr; if (!(flags & MREMAP_FIXED) || (new_addr == addr)) goto out; }