Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1317010 > unrolled thread

[RFC][PATCH 3/3] mm/page_poisoning.c: Allow for zero poisoning

Started byLaura Abbott <labbott@fedoraproject.org>
First post2016-01-25 18:00 +0100
Last post2016-01-26 02:40 +0100
Articles 4 — 4 participants

Back to article view | Back to linux.kernel

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  [RFC][PATCH 3/3] mm/page_poisoning.c: Allow for zero poisoning Laura Abbott <labbott@fedoraproject.org> - 2016-01-25 18:00 +0100
    Re: [kernel-hardening] [RFC][PATCH 3/3] mm/page_poisoning.c: Allow  for zero poisoning Dave Hansen <dave.hansen@intel.com> - 2016-01-25 21:20 +0100
      Re: [kernel-hardening] [RFC][PATCH 3/3] mm/page_poisoning.c: Allow  for zero poisoning Kees Cook <keescook@chromium.org> - 2016-01-25 23:10 +0100
        Re: [kernel-hardening] [RFC][PATCH 3/3] mm/page_poisoning.c: Allow  for zero poisoning Laura Abbott <labbott@redhat.com> - 2016-01-26 02:40 +0100

#1317010 — [RFC][PATCH 3/3] mm/page_poisoning.c: Allow for zero poisoning

FromLaura Abbott <labbott@fedoraproject.org>
Date2016-01-25 18:00 +0100
Subject[RFC][PATCH 3/3] mm/page_poisoning.c: Allow for zero poisoning
Message-ID<qUSEG-6QD-9@gated-at.bofh.it>
By default, page poisoning uses a poison value (0xaa) on free. If this
is changed to 0, the page is not only sanitized but zeroing on alloc
with __GFP_ZERO can be skipped as well. The tradeoff is that detecting
corruption from the poisoning is harder to detect. This feature also
cannot be used with hibernation since pages are not guaranteed to be
zeroed after hibernation.

Credit to Mathias Krause and grsecurity for original work

Signed-off-by: Laura Abbott <labbott@fedoraproject.org>

---
 include/linux/poison.h |  4 ++++
 mm/Kconfig.debug       | 13 +++++++++++++
 mm/page_alloc.c        |  8 +++++++-
 3 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/include/linux/poison.h b/include/linux/poison.h
index 4a27153..51334ed 100644
--- a/include/linux/poison.h
+++ b/include/linux/poison.h
@@ -30,7 +30,11 @@
 #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 ************/
 
diff --git a/mm/Kconfig.debug b/mm/Kconfig.debug
index c300f5f..8ec7dc6 100644
--- a/mm/Kconfig.debug
+++ b/mm/Kconfig.debug
@@ -48,3 +48,16 @@ config PAGE_POISONING_NO_SANITY
 
 	   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 !HIBERNATION
+	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 occuring
+	   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.
+
+	   If unsure, say N
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index c733421..7395eee 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1382,6 +1382,12 @@ static inline int check_new_page(struct page *page)
 	return 0;
 }
 
+static inline bool should_zero(void)
+{
+	return !IS_ENABLED(CONFIG_PAGE_POISONING_ZERO) ||
+		!page_poisoning_enabled();
+}
+
 static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags,
 								int alloc_flags)
 {
@@ -1401,7 +1407,7 @@ static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags,
 	kernel_map_pages(page, 1 << order, 1);
 	kasan_alloc_pages(page, order);
 
-	if (gfp_flags & __GFP_ZERO)
+	if (should_zero() && gfp_flags & __GFP_ZERO)
 		for (i = 0; i < (1 << order); i++)
 			clear_highpage(page + i);
 
-- 
2.5.0

[toc] | [next] | [standalone]


#1317272 — Re: [kernel-hardening] [RFC][PATCH 3/3] mm/page_poisoning.c: Allow for zero poisoning

FromDave Hansen <dave.hansen@intel.com>
Date2016-01-25 21:20 +0100
SubjectRe: [kernel-hardening] [RFC][PATCH 3/3] mm/page_poisoning.c: Allow for zero poisoning
Message-ID<qUVMe-PD-11@gated-at.bofh.it>
In reply to#1317010
Thanks for doing this!  It all looks pretty straightforward.

On 01/25/2016 08:55 AM, Laura Abbott wrote:
> By default, page poisoning uses a poison value (0xaa) on free. If this
> is changed to 0, the page is not only sanitized but zeroing on alloc
> with __GFP_ZERO can be skipped as well. The tradeoff is that detecting
> corruption from the poisoning is harder to detect. This feature also
> cannot be used with hibernation since pages are not guaranteed to be
> zeroed after hibernation.

Ugh, that's a good point about hibernation.  I'm not sure how widely it
gets used but it does look pretty widely enabled in distribution kernels.

Is this something that's fixable?  It seems like we could have the
hibernation code run through and zero all the free lists.  Or, we could
just disable the optimization at runtime when a hibernation is done.

Not that we _have_ to do any of this now, but if a runtime knob (like a
sysctl) could be fun too.  I would be nice for folks to turn it on and
off if they wanted the added security of "real" poisoning vs. the
potential performance boost from this optimization.

> +static inline bool should_zero(void)
> +{
> +	return !IS_ENABLED(CONFIG_PAGE_POISONING_ZERO) ||
> +		!page_poisoning_enabled();
> +}

I wonder if calling this "free_pages_prezeroed()" would make things a
bit more clear when we use it in prep_new_page().

>  static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags,
>  								int alloc_flags)
>  {
> @@ -1401,7 +1407,7 @@ static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags,
>  	kernel_map_pages(page, 1 << order, 1);
>  	kasan_alloc_pages(page, order);
>  
> -	if (gfp_flags & __GFP_ZERO)
> +	if (should_zero() && gfp_flags & __GFP_ZERO)
>  		for (i = 0; i < (1 << order); i++)
>  			clear_highpage(page + i);

It's probably also worth pointing out that this can be a really nice
feature to have in virtual machines where memory is being deduplicated.
 As it stands now, the free lists end up with gunk in them and tend not
to be easy to deduplicate.  This patch would fix that.

[toc] | [prev] | [next] | [standalone]


#1317344 — Re: [kernel-hardening] [RFC][PATCH 3/3] mm/page_poisoning.c: Allow for zero poisoning

FromKees Cook <keescook@chromium.org>
Date2016-01-25 23:10 +0100
SubjectRe: [kernel-hardening] [RFC][PATCH 3/3] mm/page_poisoning.c: Allow for zero poisoning
Message-ID<qUXuI-25U-49@gated-at.bofh.it>
In reply to#1317272
On Mon, Jan 25, 2016 at 12:16 PM, Dave Hansen <dave.hansen@intel.com> wrote:
> Thanks for doing this!  It all looks pretty straightforward.
>
> On 01/25/2016 08:55 AM, Laura Abbott wrote:
>> By default, page poisoning uses a poison value (0xaa) on free. If this
>> is changed to 0, the page is not only sanitized but zeroing on alloc
>> with __GFP_ZERO can be skipped as well. The tradeoff is that detecting
>> corruption from the poisoning is harder to detect. This feature also
>> cannot be used with hibernation since pages are not guaranteed to be
>> zeroed after hibernation.
>
> Ugh, that's a good point about hibernation.  I'm not sure how widely it
> gets used but it does look pretty widely enabled in distribution kernels.
>
> Is this something that's fixable?  It seems like we could have the
> hibernation code run through and zero all the free lists.  Or, we could
> just disable the optimization at runtime when a hibernation is done.

We can also make hibernation run-time disabled when poisoning is used
(similar to how kASLR disables it).

> Not that we _have_ to do any of this now, but if a runtime knob (like a
> sysctl) could be fun too.  I would be nice for folks to turn it on and
> off if they wanted the added security of "real" poisoning vs. the
> potential performance boost from this optimization.
>
>> +static inline bool should_zero(void)
>> +{
>> +     return !IS_ENABLED(CONFIG_PAGE_POISONING_ZERO) ||
>> +             !page_poisoning_enabled();
>> +}
>
> I wonder if calling this "free_pages_prezeroed()" would make things a
> bit more clear when we use it in prep_new_page().
>
>>  static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags,
>>                                                               int alloc_flags)
>>  {
>> @@ -1401,7 +1407,7 @@ static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags,
>>       kernel_map_pages(page, 1 << order, 1);
>>       kasan_alloc_pages(page, order);
>>
>> -     if (gfp_flags & __GFP_ZERO)
>> +     if (should_zero() && gfp_flags & __GFP_ZERO)
>>               for (i = 0; i < (1 << order); i++)
>>                       clear_highpage(page + i);
>
> It's probably also worth pointing out that this can be a really nice
> feature to have in virtual machines where memory is being deduplicated.
>  As it stands now, the free lists end up with gunk in them and tend not
> to be easy to deduplicate.  This patch would fix that.

Oh, good point!

-Kees

-- 
Kees Cook
Chrome OS & Brillo Security

[toc] | [prev] | [next] | [standalone]


#1317451 — Re: [kernel-hardening] [RFC][PATCH 3/3] mm/page_poisoning.c: Allow for zero poisoning

FromLaura Abbott <labbott@redhat.com>
Date2016-01-26 02:40 +0100
SubjectRe: [kernel-hardening] [RFC][PATCH 3/3] mm/page_poisoning.c: Allow for zero poisoning
Message-ID<qV0LV-4dv-25@gated-at.bofh.it>
In reply to#1317344
On 01/25/2016 02:05 PM, Kees Cook wrote:
> On Mon, Jan 25, 2016 at 12:16 PM, Dave Hansen <dave.hansen@intel.com> wrote:
>> Thanks for doing this!  It all looks pretty straightforward.
>>
>> On 01/25/2016 08:55 AM, Laura Abbott wrote:
>>> By default, page poisoning uses a poison value (0xaa) on free. If this
>>> is changed to 0, the page is not only sanitized but zeroing on alloc
>>> with __GFP_ZERO can be skipped as well. The tradeoff is that detecting
>>> corruption from the poisoning is harder to detect. This feature also
>>> cannot be used with hibernation since pages are not guaranteed to be
>>> zeroed after hibernation.
>>
>> Ugh, that's a good point about hibernation.  I'm not sure how widely it
>> gets used but it does look pretty widely enabled in distribution kernels.
>>
>> Is this something that's fixable?  It seems like we could have the
>> hibernation code run through and zero all the free lists.  Or, we could
>> just disable the optimization at runtime when a hibernation is done.
>
> We can also make hibernation run-time disabled when poisoning is used
> (similar to how kASLR disables it).
>

I'll look into the approach kASLR uses to disable hibernation although
having the hibernation code zero the memory could be useful as well.
We can see if there are actual complaints.
  
>> Not that we _have_ to do any of this now, but if a runtime knob (like a
>> sysctl) could be fun too.  I would be nice for folks to turn it on and
>> off if they wanted the added security of "real" poisoning vs. the
>> potential performance boost from this optimization.
>>
>>> +static inline bool should_zero(void)
>>> +{
>>> +     return !IS_ENABLED(CONFIG_PAGE_POISONING_ZERO) ||
>>> +             !page_poisoning_enabled();
>>> +}
>>
>> I wonder if calling this "free_pages_prezeroed()" would make things a
>> bit more clear when we use it in prep_new_page().
>>

Yes that sounds much better

>>>   static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags,
>>>                                                                int alloc_flags)
>>>   {
>>> @@ -1401,7 +1407,7 @@ static int prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags,
>>>        kernel_map_pages(page, 1 << order, 1);
>>>        kasan_alloc_pages(page, order);
>>>
>>> -     if (gfp_flags & __GFP_ZERO)
>>> +     if (should_zero() && gfp_flags & __GFP_ZERO)
>>>                for (i = 0; i < (1 << order); i++)
>>>                        clear_highpage(page + i);
>>
>> It's probably also worth pointing out that this can be a really nice
>> feature to have in virtual machines where memory is being deduplicated.
>>   As it stands now, the free lists end up with gunk in them and tend not
>> to be easy to deduplicate.  This patch would fix that.

Interesting, do you have any benchmarks I could test?

>
> Oh, good point!
>
> -Kees
>

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web