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


Groups > linux.kernel > #1442900 > unrolled thread

[PATCH v2 0/11] mm: Hardened usercopy

Started byKees Cook <keescook@chromium.org>
First post2016-07-14 00:00 +0200
Last post2016-07-14 00:00 +0200
Articles 10 — 3 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH v2 0/11] mm: Hardened usercopy Kees Cook <keescook@chromium.org> - 2016-07-14 00:00 +0200
    [PATCH v2 04/11] ARM: uaccess: Enable hardened usercopy Kees Cook <keescook@chromium.org> - 2016-07-14 00:00 +0200
    [PATCH v2 01/11] mm: Implement stack frame object validation Kees Cook <keescook@chromium.org> - 2016-07-14 00:00 +0200
      Re: [PATCH v2 01/11] mm: Implement stack frame object validation Kees Cook <keescook@chromium.org> - 2016-07-14 00:10 +0200
        Re: [PATCH v2 01/11] mm: Implement stack frame object validation Josh Poimboeuf <jpoimboe@redhat.com> - 2016-07-14 07:50 +0200
          Re: [PATCH v2 01/11] mm: Implement stack frame object validation Kees Cook <keescook@chromium.org> - 2016-07-14 20:20 +0200
            Re: [PATCH v2 01/11] mm: Implement stack frame object validation Josh Poimboeuf <jpoimboe@redhat.com> - 2016-07-14 21:30 +0200
              Re: [PATCH v2 01/11] mm: Implement stack frame object validation Kees Cook <keescook@chromium.org> - 2016-07-14 23:40 +0200
      Re: [PATCH v2 01/11] mm: Implement stack frame object validation Andy Lutomirski <luto@amacapital.net> - 2016-07-14 00:10 +0200
    [PATCH v2 06/11] ia64/uaccess: Enable hardened usercopy Kees Cook <keescook@chromium.org> - 2016-07-14 00:00 +0200

#1442900 — [PATCH v2 0/11] mm: Hardened usercopy

FromKees Cook <keescook@chromium.org>
Date2016-07-14 00:00 +0200
Subject[PATCH v2 0/11] mm: Hardened usercopy
Message-ID<rUAmd-nH-3@gated-at.bofh.it>
Hi,

This is a start of the mainline port of PAX_USERCOPY[1]. After I started
writing tests (now in lkdtm in -next) for Casey's earlier port[2], I
kept tweaking things further and further until I ended up with a whole
new patch series. To that end, I took Rik's feedback and made a number
of other changes and clean-ups as well.

Based on my understanding, PAX_USERCOPY was designed to catch a
few classes of flaws (mainly bad bounds checking) around the use of
copy_to_user()/copy_from_user(). These changes don't touch get_user() and
put_user(), since these operate on constant sized lengths, and tend to be
much less vulnerable. There are effectively three distinct protections in
the whole series, each of which I've given a separate CONFIG, though this
patch set is only the first of the three intended protections. (Generally
speaking, PAX_USERCOPY covers what I'm calling CONFIG_HARDENED_USERCOPY
(this) and CONFIG_HARDENED_USERCOPY_WHITELIST (future), and
PAX_USERCOPY_SLABS covers CONFIG_HARDENED_USERCOPY_SPLIT_KMALLOC
(future).)

This series, which adds CONFIG_HARDENED_USERCOPY, checks that objects
being copied to/from userspace meet certain criteria:
- if address is a heap object, the size must not exceed the object's
  allocated size. (This will catch all kinds of heap overflow flaws.)
- if address range is in the current process stack, it must be within the
  current stack frame (if such checking is possible) or at least entirely
  within the current process's stack. (This could catch large lengths that
  would have extended beyond the current process stack, or overflows if
  their length extends back into the original stack.)
- if the address range is part of kernel data, rodata, or bss, allow it.
- if address range is page-allocated, that it doesn't span multiple
  allocations.
- if address is within the kernel text, reject it.
- everything else is accepted

The patches in the series are:
- Support for arch-specific stack frame checking:
	1- mm: Implement stack frame object validation
- The core copy_to/from_user() checks, without the slab object checks:
        2- mm: Hardened usercopy
- Per-arch enablement of the protection:
        3- x86/uaccess: Enable hardened usercopy
        4- ARM: uaccess: Enable hardened usercopy
        5- arm64/uaccess: Enable hardened usercopy
        6- ia64/uaccess: Enable hardened usercopy
        7- powerpc/uaccess: Enable hardened usercopy
        8- sparc/uaccess: Enable hardened usercopy
        9- s390/uaccess: Enable hardened usercopy
- The heap allocator implementation of object size checking:
       10- mm: SLAB hardened usercopy support
       11- mm: SLUB hardened usercopy support

Some notes:

- This is expected to apply on top of -next which contains fixes for the
  position of _etext on both arm and arm64.

- I couldn't detect a measurable performance change with these features
  enabled. Kernel build times were unchanged, hackbench was unchanged,
  etc. I think we could flip this to "on by default" at some point, but
  for now, I'm leaving it off until I can get some more definitive
  measurements.

- The SLOB support extracted from grsecurity seems entirely broken. I
  have no idea what's going on there, I spent my time testing SLAB and
  SLUB. Having someone else look at SLOB would be nice, but this series
  doesn't depend on it.

Additional features that would be nice, but aren't blocking this series:

- Needs more architecture support for stack frame checking (only x86 now).


Thanks!

-Kees

[1] https://grsecurity.net/download.php "grsecurity - test kernel patch"
[2] http://www.openwall.com/lists/kernel-hardening/2016/05/19/5

v2:
- added s390 support
- handle slub red zone
- disallow writes to rodata area
- stack frame walker now CONFIG-controlled arch-specific helper

[toc] | [next] | [standalone]


#1442901 — [PATCH v2 04/11] ARM: uaccess: Enable hardened usercopy

FromKees Cook <keescook@chromium.org>
Date2016-07-14 00:00 +0200
Subject[PATCH v2 04/11] ARM: uaccess: Enable hardened usercopy
Message-ID<rUAmj-nH-29@gated-at.bofh.it>
In reply to#1442900
Enables CONFIG_HARDENED_USERCOPY checks on arm.

Based on code from PaX and grsecurity.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 arch/arm/Kconfig               |  1 +
 arch/arm/include/asm/uaccess.h | 11 +++++++++--
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 90542db1220d..f56b29b3f57e 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -35,6 +35,7 @@ config ARM
 	select HARDIRQS_SW_RESEND
 	select HAVE_ARCH_AUDITSYSCALL if (AEABI && !OABI_COMPAT)
 	select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6
+	select HAVE_ARCH_HARDENED_USERCOPY
 	select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU
 	select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32 && MMU
 	select HAVE_ARCH_MMAP_RND_BITS if MMU
diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h
index 35c9db857ebe..7fb59199c6bb 100644
--- a/arch/arm/include/asm/uaccess.h
+++ b/arch/arm/include/asm/uaccess.h
@@ -496,7 +496,10 @@ arm_copy_from_user(void *to, const void __user *from, unsigned long n);
 static inline unsigned long __must_check
 __copy_from_user(void *to, const void __user *from, unsigned long n)
 {
-	unsigned int __ua_flags = uaccess_save_and_enable();
+	unsigned int __ua_flags;
+
+	check_object_size(to, n, false);
+	__ua_flags = uaccess_save_and_enable();
 	n = arm_copy_from_user(to, from, n);
 	uaccess_restore(__ua_flags);
 	return n;
@@ -511,11 +514,15 @@ static inline unsigned long __must_check
 __copy_to_user(void __user *to, const void *from, unsigned long n)
 {
 #ifndef CONFIG_UACCESS_WITH_MEMCPY
-	unsigned int __ua_flags = uaccess_save_and_enable();
+	unsigned int __ua_flags;
+
+	check_object_size(from, n, true);
+	__ua_flags = uaccess_save_and_enable();
 	n = arm_copy_to_user(to, from, n);
 	uaccess_restore(__ua_flags);
 	return n;
 #else
+	check_object_size(from, n, true);
 	return arm_copy_to_user(to, from, n);
 #endif
 }
-- 
2.7.4

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


#1442902 — [PATCH v2 01/11] mm: Implement stack frame object validation

FromKees Cook <keescook@chromium.org>
Date2016-07-14 00:00 +0200
Subject[PATCH v2 01/11] mm: Implement stack frame object validation
Message-ID<rUAmj-nH-35@gated-at.bofh.it>
In reply to#1442900
This creates per-architecture function arch_within_stack_frames() that
should validate if a given object is contained by a kernel stack frame.
Initial implementation is on x86.

This is based on code from PaX.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 arch/Kconfig                       |  9 ++++++++
 arch/x86/Kconfig                   |  1 +
 arch/x86/include/asm/thread_info.h | 44 ++++++++++++++++++++++++++++++++++++++
 include/linux/thread_info.h        |  9 ++++++++
 4 files changed, 63 insertions(+)

diff --git a/arch/Kconfig b/arch/Kconfig
index d794384a0404..5e2776562035 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -424,6 +424,15 @@ config CC_STACKPROTECTOR_STRONG
 
 endchoice
 
+config HAVE_ARCH_WITHIN_STACK_FRAMES
+	bool
+	help
+	  An architecture should select this if it can walk the kernel stack
+	  frames to determine if an object is part of either the arguments
+	  or local variables (i.e. that it excludes saved return addresses,
+	  and similar) by implementing an inline arch_within_stack_frames(),
+	  which is used by CONFIG_HARDENED_USERCOPY.
+
 config HAVE_CONTEXT_TRACKING
 	bool
 	help
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 0a7b885964ba..4407f596b72c 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -91,6 +91,7 @@ config X86
 	select HAVE_ARCH_SOFT_DIRTY		if X86_64
 	select HAVE_ARCH_TRACEHOOK
 	select HAVE_ARCH_TRANSPARENT_HUGEPAGE
+	select HAVE_ARCH_WITHIN_STACK_FRAMES
 	select HAVE_EBPF_JIT			if X86_64
 	select HAVE_CC_STACKPROTECTOR
 	select HAVE_CMPXCHG_DOUBLE
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index 30c133ac05cd..ab386f1336f2 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -180,6 +180,50 @@ static inline unsigned long current_stack_pointer(void)
 	return sp;
 }
 
+/*
+ * Walks up the stack frames to make sure that the specified object is
+ * entirely contained by a single stack frame.
+ *
+ * Returns:
+ *		 1 if within a frame
+ *		-1 if placed across a frame boundary (or outside stack)
+ *		 0 unable to determine (no frame pointers, etc)
+ */
+static inline int arch_within_stack_frames(const void * const stack,
+					   const void * const stackend,
+					   const void *obj, unsigned long len)
+{
+#if defined(CONFIG_FRAME_POINTER)
+	const void *frame = NULL;
+	const void *oldframe;
+
+	oldframe = __builtin_frame_address(1);
+	if (oldframe)
+		frame = __builtin_frame_address(2);
+	/*
+	 * low ----------------------------------------------> high
+	 * [saved bp][saved ip][args][local vars][saved bp][saved ip]
+	 *                     ^----------------^
+	 *               allow copies only within here
+	 */
+	while (stack <= frame && frame < stackend) {
+		/*
+		 * If obj + len extends past the last frame, this
+		 * check won't pass and the next frame will be 0,
+		 * causing us to bail out and correctly report
+		 * the copy as invalid.
+		 */
+		if (obj + len <= frame)
+			return obj >= oldframe + 2 * sizeof(void *) ? 1 : -1;
+		oldframe = frame;
+		frame = *(const void * const *)frame;
+	}
+	return -1;
+#else
+	return 0;
+#endif
+}
+
 #else /* !__ASSEMBLY__ */
 
 #ifdef CONFIG_X86_64
diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h
index b4c2a485b28a..3d5c80b4391d 100644
--- a/include/linux/thread_info.h
+++ b/include/linux/thread_info.h
@@ -146,6 +146,15 @@ static inline bool test_and_clear_restore_sigmask(void)
 #error "no set_restore_sigmask() provided and default one won't work"
 #endif
 
+#ifndef CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES
+static inline int arch_within_stack_frames(const void * const stack,
+					   const void * const stackend,
+					   const void *obj, unsigned long len)
+{
+	return 0;
+}
+#endif
+
 #endif	/* __KERNEL__ */
 
 #endif /* _LINUX_THREAD_INFO_H */
-- 
2.7.4

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


#1442908 — Re: [PATCH v2 01/11] mm: Implement stack frame object validation

FromKees Cook <keescook@chromium.org>
Date2016-07-14 00:10 +0200
SubjectRe: [PATCH v2 01/11] mm: Implement stack frame object validation
Message-ID<rUAvU-Hu-15@gated-at.bofh.it>
In reply to#1442902
On Wed, Jul 13, 2016 at 3:01 PM, Andy Lutomirski <luto@amacapital.net> wrote:
> On Wed, Jul 13, 2016 at 2:55 PM, Kees Cook <keescook@chromium.org> wrote:
>> This creates per-architecture function arch_within_stack_frames() that
>> should validate if a given object is contained by a kernel stack frame.
>> Initial implementation is on x86.
>>
>> This is based on code from PaX.
>>
>
> This, along with Josh's livepatch work, are two examples of unwinders
> that matter for correctness instead of just debugging.  ISTM this
> should just use Josh's code directly once it's been written.

Do you have URL for Josh's code? I'd love to see what happening there.

In the meantime, usercopy can use this...

-Kees

-- 
Kees Cook
Chrome OS & Brillo Security

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


#1443077 — Re: [PATCH v2 01/11] mm: Implement stack frame object validation

FromJosh Poimboeuf <jpoimboe@redhat.com>
Date2016-07-14 07:50 +0200
SubjectRe: [PATCH v2 01/11] mm: Implement stack frame object validation
Message-ID<rUHH4-5oN-9@gated-at.bofh.it>
In reply to#1442908
On Wed, Jul 13, 2016 at 03:04:26PM -0700, Kees Cook wrote:
> On Wed, Jul 13, 2016 at 3:01 PM, Andy Lutomirski <luto@amacapital.net> wrote:
> > On Wed, Jul 13, 2016 at 2:55 PM, Kees Cook <keescook@chromium.org> wrote:
> >> This creates per-architecture function arch_within_stack_frames() that
> >> should validate if a given object is contained by a kernel stack frame.
> >> Initial implementation is on x86.
> >>
> >> This is based on code from PaX.
> >>
> >
> > This, along with Josh's livepatch work, are two examples of unwinders
> > that matter for correctness instead of just debugging.  ISTM this
> > should just use Josh's code directly once it's been written.
> 
> Do you have URL for Josh's code? I'd love to see what happening there.

The code is actually going to be 100% different next time around, but
FWIW, here's the last attempt:

  https://lkml.kernel.org/r/4d34d452bf8f85c7d6d5f93db1d3eeb4cba335c7.1461875890.git.jpoimboe@redhat.com

In the meantime I've realized the need to rewrite the x86 core stack
walking code to something much more manageable so we don't need all
these unwinders everywhere.  I'll probably post the patches in the next
week or so.  I'll add you to the CC list.

With the new interface I think you'll be able to do something like:

	struct unwind_state;

	unwind_start(&state, current, NULL, NULL);
	unwind_next_frame(&state);
	oldframe = unwind_get_stack_pointer(&state);

	unwind_next_frame(&state);
	frame = unwind_get_stack_pointer(&state);

	do {
		if (obj + len <= frame)
			return blah;
		oldframe = frame;
		frame = unwind_get_stack_pointer(&state);

	} while (unwind_next_frame(&state);

And then at the end there'll be some (still TBD) way to query whether it
reached the last syscall pt_regs frame, or if it instead encountered a
bogus frame pointer along the way and had to bail early.

-- 
Josh

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


#1443659 — Re: [PATCH v2 01/11] mm: Implement stack frame object validation

FromKees Cook <keescook@chromium.org>
Date2016-07-14 20:20 +0200
SubjectRe: [PATCH v2 01/11] mm: Implement stack frame object validation
Message-ID<rUToS-4Fx-11@gated-at.bofh.it>
In reply to#1443077
On Wed, Jul 13, 2016 at 10:48 PM, Josh Poimboeuf <jpoimboe@redhat.com> wrote:
> On Wed, Jul 13, 2016 at 03:04:26PM -0700, Kees Cook wrote:
>> On Wed, Jul 13, 2016 at 3:01 PM, Andy Lutomirski <luto@amacapital.net> wrote:
>> > On Wed, Jul 13, 2016 at 2:55 PM, Kees Cook <keescook@chromium.org> wrote:
>> >> This creates per-architecture function arch_within_stack_frames() that
>> >> should validate if a given object is contained by a kernel stack frame.
>> >> Initial implementation is on x86.
>> >>
>> >> This is based on code from PaX.
>> >>
>> >
>> > This, along with Josh's livepatch work, are two examples of unwinders
>> > that matter for correctness instead of just debugging.  ISTM this
>> > should just use Josh's code directly once it's been written.
>>
>> Do you have URL for Josh's code? I'd love to see what happening there.
>
> The code is actually going to be 100% different next time around, but
> FWIW, here's the last attempt:
>
>   https://lkml.kernel.org/r/4d34d452bf8f85c7d6d5f93db1d3eeb4cba335c7.1461875890.git.jpoimboe@redhat.com
>
> In the meantime I've realized the need to rewrite the x86 core stack
> walking code to something much more manageable so we don't need all
> these unwinders everywhere.  I'll probably post the patches in the next
> week or so.  I'll add you to the CC list.

Awesome!

> With the new interface I think you'll be able to do something like:
>
>         struct unwind_state;
>
>         unwind_start(&state, current, NULL, NULL);
>         unwind_next_frame(&state);
>         oldframe = unwind_get_stack_pointer(&state);
>
>         unwind_next_frame(&state);
>         frame = unwind_get_stack_pointer(&state);
>
>         do {
>                 if (obj + len <= frame)
>                         return blah;
>                 oldframe = frame;
>                 frame = unwind_get_stack_pointer(&state);
>
>         } while (unwind_next_frame(&state);
>
> And then at the end there'll be some (still TBD) way to query whether it
> reached the last syscall pt_regs frame, or if it instead encountered a
> bogus frame pointer along the way and had to bail early.

Sounds good to me. Will there be any frame size information available?
Right now, the unwinder from PaX just drops 2 pointers (saved frame,
saved ip) from the delta of frame address to find the size of the
actual stack area used by the function. If I could shave things like
padding and possible stack canaries off the size too, that would be
great.

Since I'm aiming the hardened usercopy series for 4.8, I figure I'll
just leave this unwinder in for now, and once yours lands, I can rip
it out again.

-Kees

-- 
Kees Cook
Chrome OS & Brillo Security

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


#1443713 — Re: [PATCH v2 01/11] mm: Implement stack frame object validation

FromJosh Poimboeuf <jpoimboe@redhat.com>
Date2016-07-14 21:30 +0200
SubjectRe: [PATCH v2 01/11] mm: Implement stack frame object validation
Message-ID<rUUuB-5j0-13@gated-at.bofh.it>
In reply to#1443659
On Thu, Jul 14, 2016 at 11:10:18AM -0700, Kees Cook wrote:
> On Wed, Jul 13, 2016 at 10:48 PM, Josh Poimboeuf <jpoimboe@redhat.com> wrote:
> > On Wed, Jul 13, 2016 at 03:04:26PM -0700, Kees Cook wrote:
> >> On Wed, Jul 13, 2016 at 3:01 PM, Andy Lutomirski <luto@amacapital.net> wrote:
> >> > On Wed, Jul 13, 2016 at 2:55 PM, Kees Cook <keescook@chromium.org> wrote:
> >> >> This creates per-architecture function arch_within_stack_frames() that
> >> >> should validate if a given object is contained by a kernel stack frame.
> >> >> Initial implementation is on x86.
> >> >>
> >> >> This is based on code from PaX.
> >> >>
> >> >
> >> > This, along with Josh's livepatch work, are two examples of unwinders
> >> > that matter for correctness instead of just debugging.  ISTM this
> >> > should just use Josh's code directly once it's been written.
> >>
> >> Do you have URL for Josh's code? I'd love to see what happening there.
> >
> > The code is actually going to be 100% different next time around, but
> > FWIW, here's the last attempt:
> >
> >   https://lkml.kernel.org/r/4d34d452bf8f85c7d6d5f93db1d3eeb4cba335c7.1461875890.git.jpoimboe@redhat.com
> >
> > In the meantime I've realized the need to rewrite the x86 core stack
> > walking code to something much more manageable so we don't need all
> > these unwinders everywhere.  I'll probably post the patches in the next
> > week or so.  I'll add you to the CC list.
> 
> Awesome!
> 
> > With the new interface I think you'll be able to do something like:
> >
> >         struct unwind_state;
> >
> >         unwind_start(&state, current, NULL, NULL);
> >         unwind_next_frame(&state);
> >         oldframe = unwind_get_stack_pointer(&state);
> >
> >         unwind_next_frame(&state);
> >         frame = unwind_get_stack_pointer(&state);
> >
> >         do {
> >                 if (obj + len <= frame)
> >                         return blah;
> >                 oldframe = frame;
> >                 frame = unwind_get_stack_pointer(&state);
> >
> >         } while (unwind_next_frame(&state);
> >
> > And then at the end there'll be some (still TBD) way to query whether it
> > reached the last syscall pt_regs frame, or if it instead encountered a
> > bogus frame pointer along the way and had to bail early.
> 
> Sounds good to me. Will there be any frame size information available?
> Right now, the unwinder from PaX just drops 2 pointers (saved frame,
> saved ip) from the delta of frame address to find the size of the
> actual stack area used by the function. If I could shave things like
> padding and possible stack canaries off the size too, that would be
> great.

For x86, stacks are aligned at long word boundaries, so there's no real
stack padding.

Also the CC_STACKPROTECTOR stack canaries are created by a gcc feature
which only affects certain functions (and thus certain frames) and I
don't know of any reliable way to find them.

So with frame pointers, I think the best you can do is just assume that
the frame data area is always two words smaller than the total frame
size.

> Since I'm aiming the hardened usercopy series for 4.8, I figure I'll
> just leave this unwinder in for now, and once yours lands, I can rip
> it out again.

Sure, sounds fine to me.  If your code lands before I post mine, I can
convert it myself.

-- 
Josh

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


#1443792 — Re: [PATCH v2 01/11] mm: Implement stack frame object validation

FromKees Cook <keescook@chromium.org>
Date2016-07-14 23:40 +0200
SubjectRe: [PATCH v2 01/11] mm: Implement stack frame object validation
Message-ID<rUWwp-6vr-9@gated-at.bofh.it>
In reply to#1443713
On Thu, Jul 14, 2016 at 12:23 PM, Josh Poimboeuf <jpoimboe@redhat.com> wrote:
> On Thu, Jul 14, 2016 at 11:10:18AM -0700, Kees Cook wrote:
>> On Wed, Jul 13, 2016 at 10:48 PM, Josh Poimboeuf <jpoimboe@redhat.com> wrote:
>> > On Wed, Jul 13, 2016 at 03:04:26PM -0700, Kees Cook wrote:
>> >> On Wed, Jul 13, 2016 at 3:01 PM, Andy Lutomirski <luto@amacapital.net> wrote:
>> >> > On Wed, Jul 13, 2016 at 2:55 PM, Kees Cook <keescook@chromium.org> wrote:
>> >> >> This creates per-architecture function arch_within_stack_frames() that
>> >> >> should validate if a given object is contained by a kernel stack frame.
>> >> >> Initial implementation is on x86.
>> >> >>
>> >> >> This is based on code from PaX.
>> >> >>
>> >> >
>> >> > This, along with Josh's livepatch work, are two examples of unwinders
>> >> > that matter for correctness instead of just debugging.  ISTM this
>> >> > should just use Josh's code directly once it's been written.
>> >>
>> >> Do you have URL for Josh's code? I'd love to see what happening there.
>> >
>> > The code is actually going to be 100% different next time around, but
>> > FWIW, here's the last attempt:
>> >
>> >   https://lkml.kernel.org/r/4d34d452bf8f85c7d6d5f93db1d3eeb4cba335c7.1461875890.git.jpoimboe@redhat.com
>> >
>> > In the meantime I've realized the need to rewrite the x86 core stack
>> > walking code to something much more manageable so we don't need all
>> > these unwinders everywhere.  I'll probably post the patches in the next
>> > week or so.  I'll add you to the CC list.
>>
>> Awesome!
>>
>> > With the new interface I think you'll be able to do something like:
>> >
>> >         struct unwind_state;
>> >
>> >         unwind_start(&state, current, NULL, NULL);
>> >         unwind_next_frame(&state);
>> >         oldframe = unwind_get_stack_pointer(&state);
>> >
>> >         unwind_next_frame(&state);
>> >         frame = unwind_get_stack_pointer(&state);
>> >
>> >         do {
>> >                 if (obj + len <= frame)
>> >                         return blah;
>> >                 oldframe = frame;
>> >                 frame = unwind_get_stack_pointer(&state);
>> >
>> >         } while (unwind_next_frame(&state);
>> >
>> > And then at the end there'll be some (still TBD) way to query whether it
>> > reached the last syscall pt_regs frame, or if it instead encountered a
>> > bogus frame pointer along the way and had to bail early.
>>
>> Sounds good to me. Will there be any frame size information available?
>> Right now, the unwinder from PaX just drops 2 pointers (saved frame,
>> saved ip) from the delta of frame address to find the size of the
>> actual stack area used by the function. If I could shave things like
>> padding and possible stack canaries off the size too, that would be
>> great.
>
> For x86, stacks are aligned at long word boundaries, so there's no real
> stack padding.

Well, I guess I meant the possible padding between variables and the
aligned pointers, but that's a really minor concern in my mind (as far
as being a potential kernel memory exposure on a bad usercopy).

> Also the CC_STACKPROTECTOR stack canaries are created by a gcc feature
> which only affects certain functions (and thus certain frames) and I
> don't know of any reliable way to find them.

Okay, that's fine. I had a horrible idea to just have the unwinder
look at the value stored in front of the saved ip, and if it matches
the known canary (for current anyway), then reduce the frame size by
another long word. ;)

> So with frame pointers, I think the best you can do is just assume that
> the frame data area is always two words smaller than the total frame
> size.

Yeah, that's what's happening here currently. Cool.

>> Since I'm aiming the hardened usercopy series for 4.8, I figure I'll
>> just leave this unwinder in for now, and once yours lands, I can rip
>> it out again.
>
> Sure, sounds fine to me.  If your code lands before I post mine, I can
> convert it myself.

Awesome, I'll keep you posted. Thanks!

-Kees

-- 
Kees Cook
Chrome OS & Brillo Security

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


#1442909 — Re: [PATCH v2 01/11] mm: Implement stack frame object validation

FromAndy Lutomirski <luto@amacapital.net>
Date2016-07-14 00:10 +0200
SubjectRe: [PATCH v2 01/11] mm: Implement stack frame object validation
Message-ID<rUAvU-Hu-17@gated-at.bofh.it>
In reply to#1442902
On Wed, Jul 13, 2016 at 2:55 PM, Kees Cook <keescook@chromium.org> wrote:
> This creates per-architecture function arch_within_stack_frames() that
> should validate if a given object is contained by a kernel stack frame.
> Initial implementation is on x86.
>
> This is based on code from PaX.
>

This, along with Josh's livepatch work, are two examples of unwinders
that matter for correctness instead of just debugging.  ISTM this
should just use Josh's code directly once it's been written.

--Andy

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


#1442903 — [PATCH v2 06/11] ia64/uaccess: Enable hardened usercopy

FromKees Cook <keescook@chromium.org>
Date2016-07-14 00:00 +0200
Subject[PATCH v2 06/11] ia64/uaccess: Enable hardened usercopy
Message-ID<rUAmj-nH-37@gated-at.bofh.it>
In reply to#1442900
Enables CONFIG_HARDENED_USERCOPY checks on ia64.

Based on code from PaX and grsecurity.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 arch/ia64/Kconfig               |  1 +
 arch/ia64/include/asm/uaccess.h | 18 +++++++++++++++---
 2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index f80758cb7157..32a87ef516a0 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -53,6 +53,7 @@ config IA64
 	select MODULES_USE_ELF_RELA
 	select ARCH_USE_CMPXCHG_LOCKREF
 	select HAVE_ARCH_AUDITSYSCALL
+	select HAVE_ARCH_HARDENED_USERCOPY
 	default y
 	help
 	  The Itanium Processor Family is Intel's 64-bit successor to
diff --git a/arch/ia64/include/asm/uaccess.h b/arch/ia64/include/asm/uaccess.h
index 2189d5ddc1ee..465c70982f40 100644
--- a/arch/ia64/include/asm/uaccess.h
+++ b/arch/ia64/include/asm/uaccess.h
@@ -241,12 +241,18 @@ extern unsigned long __must_check __copy_user (void __user *to, const void __use
 static inline unsigned long
 __copy_to_user (void __user *to, const void *from, unsigned long count)
 {
+	if (!__builtin_constant_p(count))
+		check_object_size(from, count, true);
+
 	return __copy_user(to, (__force void __user *) from, count);
 }
 
 static inline unsigned long
 __copy_from_user (void *to, const void __user *from, unsigned long count)
 {
+	if (!__builtin_constant_p(count))
+		check_object_size(to, count, false);
+
 	return __copy_user((__force void __user *) to, from, count);
 }
 
@@ -258,8 +264,11 @@ __copy_from_user (void *to, const void __user *from, unsigned long count)
 	const void *__cu_from = (from);							\
 	long __cu_len = (n);								\
 											\
-	if (__access_ok(__cu_to, __cu_len, get_fs()))					\
-		__cu_len = __copy_user(__cu_to, (__force void __user *) __cu_from, __cu_len);	\
+	if (__access_ok(__cu_to, __cu_len, get_fs())) {					\
+		if (!__builtin_constant_p(n))						\
+			check_object_size(__cu_from, __cu_len, true);			\
+		__cu_len = __copy_user(__cu_to, (__force void __user *)  __cu_from, __cu_len);	\
+	}										\
 	__cu_len;									\
 })
 
@@ -270,8 +279,11 @@ __copy_from_user (void *to, const void __user *from, unsigned long count)
 	long __cu_len = (n);								\
 											\
 	__chk_user_ptr(__cu_from);							\
-	if (__access_ok(__cu_from, __cu_len, get_fs()))					\
+	if (__access_ok(__cu_from, __cu_len, get_fs())) {				\
+		if (!__builtin_constant_p(n))						\
+			check_object_size(__cu_to, __cu_len, false);			\
 		__cu_len = __copy_user((__force void __user *) __cu_to, __cu_from, __cu_len);	\
+	}										\
 	__cu_len;									\
 })
 
-- 
2.7.4

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web