diff options
author | Liu Zixian <liuzixian4@huawei.com> | 2020-12-05 22:15:15 -0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2020-12-16 10:58:29 +0100 |
commit | dd81cf1cd50021b8dd65ae0cef0ec80c86b11d3e (patch) | |
tree | 1a5c4c03bef9a8c75ce3d49aa409e351fe3f2b22 /mm | |
parent | cd8c84007bdc82e8fc0559a6523062abf6daae5f (diff) | |
download | linux-stable-dd81cf1cd50021b8dd65ae0cef0ec80c86b11d3e.tar.gz linux-stable-dd81cf1cd50021b8dd65ae0cef0ec80c86b11d3e.tar.bz2 linux-stable-dd81cf1cd50021b8dd65ae0cef0ec80c86b11d3e.zip |
mm/mmap.c: fix mmap return value when vma is merged after call_mmap()
[ Upstream commit 309d08d9b3a3659ab3f239d27d4e38b670b08fc9 ]
On success, mmap should return the begin address of newly mapped area,
but patch "mm: mmap: merge vma after call_mmap() if possible" set
vm_start of newly merged vma to return value addr. Users of mmap will
get wrong address if vma is merged after call_mmap(). We fix this by
moving the assignment to addr before merging vma.
We have a driver which changes vm_flags, and this bug is found by our
testcases.
Fixes: d70cec898324 ("mm: mmap: merge vma after call_mmap() if possible")
Signed-off-by: Liu Zixian <liuzixian4@huawei.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Cc: Hongxiang Lou <louhongxiang@huawei.com>
Cc: Hu Shiyuan <hushiyuan@huawei.com>
Cc: Matthew Wilcox <willy@infradead.org>
Link: https://lkml.kernel.org/r/20201203085350.22624-1-liuzixian4@huawei.com
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/mmap.c | 26 |
1 files changed, 12 insertions, 14 deletions
diff --git a/mm/mmap.c b/mm/mmap.c index 7a8987aa6996..c85a2875a962 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1774,6 +1774,17 @@ unsigned long mmap_region(struct file *file, unsigned long addr, if (error) goto unmap_and_free_vma; + /* Can addr have changed?? + * + * Answer: Yes, several device drivers can do it in their + * f_op->mmap method. -DaveM + * Bug: If addr is changed, prev, rb_link, rb_parent should + * be updated for vma_link() + */ + WARN_ON_ONCE(addr != vma->vm_start); + + addr = vma->vm_start; + /* If vm_flags changed after call_mmap(), we should try merge vma again * as we may succeed this time. */ @@ -1788,25 +1799,12 @@ unsigned long mmap_region(struct file *file, unsigned long addr, fput(vma->vm_file); vm_area_free(vma); vma = merge; - /* Update vm_flags and possible addr to pick up the change. We don't - * warn here if addr changed as the vma is not linked by vma_link(). - */ - addr = vma->vm_start; + /* Update vm_flags to pick up the change. */ vm_flags = vma->vm_flags; goto unmap_writable; } } - /* Can addr have changed?? - * - * Answer: Yes, several device drivers can do it in their - * f_op->mmap method. -DaveM - * Bug: If addr is changed, prev, rb_link, rb_parent should - * be updated for vma_link() - */ - WARN_ON_ONCE(addr != vma->vm_start); - - addr = vma->vm_start; vm_flags = vma->vm_flags; } else if (vm_flags & VM_SHARED) { error = shmem_zero_setup(vma); |