On Wed, Feb 21, 2024 at 10:38:27AM -0500, Liam R. Howlett wrote:
* Yajun Deng <yajun.deng@xxxxxxxxx> [240221 04:15]:I definitely agree with Liam that this should not be in vma_merge(), as
In most cases, the range of the area is valid. But in do_mprotect_pkey(),If it's only one caller, could we stop that caller instead of checking
the minimum value of end and vma->vm_end is passed to mprotect_fixup().
This will lead to the end is less than the end of prev.
In this case, the curr will be NULL, but the next will be equal to the
prev. So it will attempt to merge before, the vm_pgoff check will cause
this case to fail.
To avoid the process described above and reduce unnecessary operations.
Add a check to immediately return NULL if the end is less than the end of
prev.
an almost never case for all callers? Would this better fit in
vma_modify()? Although that's not just for this caller at this point.
Maybe there isn't a good place?
it's not going to be relevant to _most_ callers.
I am not sure vma_modify() is much better, this would be the only early
exit check in that function and makes what is very simple and
straightforward now more confusing.
And I think this is the crux of it - it's confusing that we special case
this one particular non-merge scenario, but no others (all of which we then
deem ok to be caught by the usual rules).
I think it's simpler (and more efficient) to just keep things the way they
are.
Or are there other reasons this may happen and is better done in thisSo overall I don't think this check makes much sense anywhere.
function?
Often, this is called the "punch a hole" scenario; where an operation
creates two entries from the old data and either leaves an empty space
or fills the space with a new VMA.
Signed-off-by: Yajun Deng <yajun.deng@xxxxxxxxx>
---
v2: remove the case label.
v1: https://lore.kernel.org/all/20240218085028.3294332-1-yajun.deng@xxxxxxxxx/
---
mm/mmap.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/mm/mmap.c b/mm/mmap.c
index 0fccd23f056e..7668854d2246 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -890,6 +890,9 @@ static struct vm_area_struct
if (vm_flags & VM_SPECIAL)
return NULL;
+ if (prev && end < prev->vm_end)
+ return NULL;
+
/* Does the input range span an existing VMA? (cases 5 - 8) */
curr = find_vma_intersection(mm, prev ? prev->vm_end : 0, end);
--
2.25.1
I think a better solution would be to prevent it happening _at source_ if
you can find a logical way of doing so.
I do plan to do some cleanup passes over this stuff once again so maybe I
can figure something out that better handles non-merge scenarios.
This is a great find though overall even if a patch doesn't make sense
Yajun, thanks for this, it's really made me think about this case (+ others
like it) :)