Skip to content

Commit

Permalink
mm/mlock.c: prevent walking off the end of a pagetable in no-pmd conf…
Browse files Browse the repository at this point in the history
…iguration

The function __munlock_pagevec_fill() introduced in commit 7a8010c
("mm: munlock: manual pte walk in fast path instead of
follow_page_mask()") uses pmd_addr_end() for restricting its operation
within current page table.

This is insufficient on architectures/configurations where pmd is folded
and pmd_addr_end() just returns the end of the full range to be walked.
In this case, it allows pte++ to walk off the end of a page table
resulting in unpredictable behaviour.

This patch fixes the function by using pgd_addr_end() and pud_addr_end()
before pmd_addr_end(), which will yield correct page table boundary on
all configurations.  This is similar to what existing page walkers do
when walking each level of the page table.

Additionaly, the patch clarifies a comment for get_locked_pte() call in the
function.

Signed-off-by: Vlastimil Babka <[email protected]>
Reported-by: Fengguang Wu <[email protected]>
Reviewed-by: Bob Liu <[email protected]>
Cc: Jörn Engel <[email protected]>
Cc: Mel Gorman <[email protected]>
Cc: Michel Lespinasse <[email protected]>
Cc: Hugh Dickins <[email protected]>
Cc: Rik van Riel <[email protected]>
Cc: Johannes Weiner <[email protected]>
Cc: Michal Hocko <[email protected]>
Cc: Vlastimil Babka <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
tehcaster authored and torvalds committed Sep 30, 2013
1 parent 117aad1 commit eadb41a
Showing 1 changed file with 6 additions and 2 deletions.
8 changes: 6 additions & 2 deletions mm/mlock.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,10 +379,14 @@ static unsigned long __munlock_pagevec_fill(struct pagevec *pvec,

/*
* Initialize pte walk starting at the already pinned page where we
* are sure that there is a pte.
* are sure that there is a pte, as it was pinned under the same
* mmap_sem write op.
*/
pte = get_locked_pte(vma->vm_mm, start, &ptl);
end = min(end, pmd_addr_end(start, end));
/* Make sure we do not cross the page table boundary */
end = pgd_addr_end(start, end);
end = pud_addr_end(start, end);
end = pmd_addr_end(start, end);

/* The page next to the pinned page is the first we will try to get */
start += PAGE_SIZE;
Expand Down

0 comments on commit eadb41a

Please sign in to comment.