]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
mm: sanitize page->mapping for tail pages
authorKirill A. Shutemov <kirill.shutemov@linux.intel.com>
Wed, 21 Oct 2015 22:03:35 +0000 (09:03 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Wed, 21 Oct 2015 22:03:35 +0000 (09:03 +1100)
We don't define meaning of page->mapping for tail pages.  Currently it's
always NULL, which can be inconsistent with head page and potentially lead
to problems.

Let's poison the pointer to catch all illigal uses.

page_rmapping(), page_mapping() and page_anon_vma() are changed to look on
head page.

The only illegal use I've caught so far is __GPF_COMP pages from sound
subsystem, mapped with PTEs.  do_shared_fault() is changed to use
page_rmapping() instead of direct access to fault_page->mapping.

Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Reviewed-by: Jérôme Glisse <jglisse@redhat.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Rik van Riel <riel@redhat.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Christoph Lameter <cl@linux.com>
Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Cc: Steve Capper <steve.capper@linaro.org>
Cc: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Michal Hocko <mhocko@suse.cz>
Cc: Jerome Marchand <jmarchan@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
include/linux/poison.h
mm/huge_memory.c
mm/memory.c
mm/page_alloc.c
mm/util.c

index 317e16de09e508ed64b87dae6c5006b1efcb129d..76c3b6c38c16e341ce8952ba988543a230d800de 100644 (file)
 /********** mm/debug-pagealloc.c **********/
 #define PAGE_POISON 0xaa
 
+/********** mm/page_alloc.c ************/
+
+#define TAIL_MAPPING   ((void *) 0x01014A11 + POISON_POINTER_DELTA)
+
 /********** mm/slab.c **********/
 /*
  * Magic nums for obj red zoning.
index 0524792f3da5c4b8f49a03be79c994d045f13dfa..7849b1208d84f0c8b6cf30fb25c4f0a7667b2616 100644 (file)
@@ -1836,7 +1836,7 @@ static void __split_huge_page_refcount(struct page *page,
                */
                page_tail->_mapcount = page->_mapcount;
 
-               BUG_ON(page_tail->mapping);
+               BUG_ON(page_tail->mapping != TAIL_MAPPING);
                page_tail->mapping = page->mapping;
 
                page_tail->index = page->index + i;
index 84ee4511608063e2c877d7e1d98a52d0439f3df6..f1c9463747d4b0478d6bbf47b87f7900aa937b62 100644 (file)
@@ -3089,7 +3089,7 @@ static int do_shared_fault(struct mm_struct *mm, struct vm_area_struct *vma,
         * pinned by vma->vm_file's reference.  We rely on unlock_page()'s
         * release semantics to prevent the compiler from undoing this copying.
         */
-       mapping = fault_page->mapping;
+       mapping = page_rmapping(fault_page);
        unlock_page(fault_page);
        if ((dirtied || vma->vm_ops->page_mkwrite) && mapping) {
                /*
index 94bb8a0bfcdae720325577cdcf843eba57e21f78..ac4ddef63771433ca4fda536aba767e385dcd12a 100644 (file)
@@ -473,6 +473,7 @@ void prep_compound_page(struct page *page, unsigned int order)
        for (i = 1; i < nr_pages; i++) {
                struct page *p = page + i;
                set_page_count(p, 0);
+               p->mapping = TAIL_MAPPING;
                set_compound_head(p, page);
        }
 }
@@ -863,6 +864,10 @@ static int free_tail_pages_check(struct page *head_page, struct page *page)
                ret = 0;
                goto out;
        }
+       if (page->mapping != TAIL_MAPPING) {
+               bad_page(page, "corrupted mapping in tail page", 0);
+               goto out;
+       }
        if (unlikely(!PageTail(page))) {
                bad_page(page, "PageTail not set", 0);
                goto out;
@@ -873,6 +878,7 @@ static int free_tail_pages_check(struct page *head_page, struct page *page)
        }
        ret = 0;
 out:
+       page->mapping = NULL;
        clear_compound_head(page);
        return ret;
 }
index 9af1c12b310c7f092f030fc1a4303c287724b0a6..902b65a438991fb9bedc45f1a16700e0e53f50c4 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -355,7 +355,9 @@ struct anon_vma *page_anon_vma(struct page *page)
 
 struct address_space *page_mapping(struct page *page)
 {
-       unsigned long mapping;
+       struct address_space *mapping;
+
+       page = compound_head(page);
 
        /* This happens if someone calls flush_dcache_page on slab page */
        if (unlikely(PageSlab(page)))
@@ -368,10 +370,10 @@ struct address_space *page_mapping(struct page *page)
                return swap_address_space(entry);
        }
 
-       mapping = (unsigned long)page->mapping;
-       if (mapping & PAGE_MAPPING_FLAGS)
+       mapping = page->mapping;
+       if ((unsigned long)mapping & PAGE_MAPPING_FLAGS)
                return NULL;
-       return page->mapping;
+       return mapping;
 }
 
 int overcommit_ratio_handler(struct ctl_table *table, int write,