#ifdef CONFIG_PAGE_POISONING
 extern bool page_poisoning_enabled(void);
 extern void kernel_poison_pages(struct page *page, int numpages, int enable);
+extern bool page_is_poisoned(struct page *page);
 #else
 static inline bool page_poisoning_enabled(void) { return false; }
 static inline void kernel_poison_pages(struct page *page, int numpages,
                                        int enable) { }
+static inline bool page_is_poisoned(struct page *page) { return false; }
 #endif
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
 
 #define TIMER_ENTRY_STATIC     ((void *) 0x300 + POISON_POINTER_DELTA)
 
 /********** mm/debug-pagealloc.c **********/
+#ifdef CONFIG_PAGE_POISONING_ZERO
+#define PAGE_POISON 0x00
+#else
 #define PAGE_POISON 0xaa
+#endif
 
 /********** mm/page_alloc.c ************/
 
 
        return nohibernate_setup(str);
 }
 
+static int __init page_poison_nohibernate_setup(char *str)
+{
+#ifdef CONFIG_PAGE_POISONING_ZERO
+       /*
+        * The zeroing option for page poison skips the checks on alloc.
+        * since hibernation doesn't save free pages there's no way to
+        * guarantee the pages will still be zeroed.
+        */
+       if (!strcmp(str, "on")) {
+               pr_info("Disabling hibernation due to page poisoning\n");
+               return nohibernate_setup(str);
+       }
+#endif
+       return 1;
+}
+
 __setup("noresume", noresume_setup);
 __setup("resume_offset=", resume_offset_setup);
 __setup("resume=", resume_setup);
 __setup("resumedelay=", resumedelay_setup);
 __setup("nohibernate", nohibernate_setup);
 __setup("kaslr", kaslr_nohibernate_setup);
+__setup("page_poison=", page_poison_nohibernate_setup);
 
 
           If you are only interested in sanitization, say Y. Otherwise
           say N.
+
+config PAGE_POISONING_ZERO
+       bool "Use zero for poisoning instead of random data"
+       depends on PAGE_POISONING
+       ---help---
+          Instead of using the existing poison value, fill the pages with
+          zeros. This makes it harder to detect when errors are occurring
+          due to sanitization but the zeroing at free means that it is
+          no longer necessary to write zeros when GFP_ZERO is used on
+          allocation.
+
+          Enabling page poisoning with this option will disable hibernation
+
+          If unsure, say N
 
        return 0;
 }
 
+static inline bool free_pages_prezeroed(bool poisoned)
+{
+       return IS_ENABLED(CONFIG_PAGE_POISONING_ZERO) &&
+               page_poisoning_enabled() && poisoned;
+}
+
 static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags,
                                                                int alloc_flags)
 {
        int i;
+       bool poisoned = true;
 
        for (i = 0; i < (1 << order); i++) {
                struct page *p = page + i;
                if (unlikely(check_new_page(p)))
                        return 1;
+               if (poisoned)
+                       poisoned &= page_is_poisoned(p);
        }
 
        set_page_private(page, 0);
        kernel_poison_pages(page, 1 << order, 1);
        kasan_alloc_pages(page, order);
 
-       if (gfp_flags & __GFP_ZERO)
+       if (!free_pages_prezeroed(poisoned) && (gfp_flags & __GFP_ZERO))
                for (i = 0; i < (1 << order); i++)
                        clear_highpage(page + i);
 
 
        struct page_ext *base;
 
        base = NODE_DATA(page_to_nid(page))->node_page_ext;
-#ifdef CONFIG_DEBUG_VM
+#if defined(CONFIG_DEBUG_VM) || defined(CONFIG_PAGE_POISONING)
        /*
         * The sanity checks the page allocator does upon freeing a
         * page can reach here before the page_ext arrays are
         * allocated when feeding a range of pages to the allocator
         * for the first time during bootup or memory hotplug.
+        *
+        * This check is also necessary for ensuring page poisoning
+        * works as expected when enabled
         */
        if (unlikely(!base))
                return NULL;
 {
        unsigned long pfn = page_to_pfn(page);
        struct mem_section *section = __pfn_to_section(pfn);
-#ifdef CONFIG_DEBUG_VM
+#if defined(CONFIG_DEBUG_VM) || defined(CONFIG_PAGE_POISONING)
        /*
         * The sanity checks the page allocator does upon freeing a
         * page can reach here before the page_ext arrays are
         * allocated when feeding a range of pages to the allocator
         * for the first time during bootup or memory hotplug.
+        *
+        * This check is also necessary for ensuring page poisoning
+        * works as expected when enabled
         */
        if (!section->page_ext)
                return NULL;
 
        __clear_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
 }
 
-static inline bool page_poison(struct page *page)
+bool page_is_poisoned(struct page *page)
 {
        struct page_ext *page_ext;
 
        page_ext = lookup_page_ext(page);
+       if (!page_ext)
+               return false;
+
        return test_bit(PAGE_EXT_DEBUG_POISON, &page_ext->flags);
 }
 
 {
        void *addr;
 
-       if (!page_poison(page))
+       if (!page_is_poisoned(page))
                return;
 
        addr = kmap_atomic(page);