linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Does CONFIG_HARDENED_USERCOPY break /dev/mem?
@ 2017-11-10 15:45 Michael Holzheu
  2017-11-10 18:46 ` Kees Cook
  0 siblings, 1 reply; 7+ messages in thread
From: Michael Holzheu @ 2017-11-10 15:45 UTC (permalink / raw)
  To: Kees Cook
  Cc: Arnd Bergmann, Greg Kroah-Hartman, linux-kernel, Heiko Carstens,
	Martin Schwidefsky, Vasily Gorbik

Hello Kees,

When I try to run the crash tool on my s390 live system I get a kernel panic
when reading memory within the kernel image:

 # uname -a
   Linux r3545011 4.14.0-rc8-00066-g1c9dbd4615fd #45 SMP PREEMPT Fri Nov 10 16:16:22 CET 2017 s390x s390x s390x GNU/Linux
 # crash /boot/vmlinux-devel /dev/mem
 # crash> rd 0x100000

 usercopy: kernel memory exposure attempt detected from 0000000000100000 (<kernel text>) (8 bytes)
 ------------[ cut here ]------------
 kernel BUG at mm/usercopy.c:72! 
 illegal operation: 0001 ilc:1 [#1] PREEMPT SMP.
 Modules linked in:
 CPU: 0 PID: 1461 Comm: crash Not tainted 4.14.0-rc8-00066-g1c9dbd4615fd-dirty #46
 Hardware name: IBM 2827 H66 706 (z/VM 6.3.0)
 task: 000000001ad10100 task.stack: 000000001df78000 
 Krnl PSW : 0704d00180000000 000000000038165c (__check_object_size+0x164/0x1d0)
            R:0 T:1 IO:1 EX:1 Key:0 M:1 W:0 P:0 AS:3 CC:1 PM:0 RI:0 EA:3
 Krnl GPRS: 0000000012440e1d 0000000080000000 0000000000000061 00000000001cabc0
            00000000001cc6d6 0000000000000000 0000000000cc4ed2 0000000000001000
            000003ffc22fdd20 0000000000000008 0000000000100008 0000000000000001
            0000000000000008 0000000000100000 0000000000381658 000000001df7bc90
 Krnl Code: 000000000038164c: c020004a1c4a        larl    %r2,cc4ee0
            0000000000381652: c0e5fff2581b        brasl   %r14,1cc688   
           #0000000000381658: a7f40001            brc     15,38165a
           >000000000038165c: eb42000c000c        srlg    %r4,%r2,12    
            0000000000381662: eb32001c000c        srlg    %r3,%r2,28    
            0000000000381668: c0110003ffff        lgfi    %r1,262143    
            000000000038166e: ec31ff752065        clgrj   %r3,%r1,2,381558
            0000000000381674: a7f4ff67            brc     15,381542
 Call Trace:
 ([<0000000000381658>] __check_object_size+0x160/0x1d0)
  [<000000000082263a>] read_mem+0xaa/0x130.
  [<0000000000386182>] __vfs_read+0x42/0x168.
  [<000000000038632e>] vfs_read+0x86/0x140.
  [<0000000000386a26>] SyS_read+0x66/0xc0.
  [<0000000000ace6a4>] system_call+0xc4/0x2b0.
 INFO: lockdep is turned off.
 Last Breaking-Event-Address:
  [<0000000000381658>] __check_object_size+0x160/0x1d0

 Kernel panic - not syncing: Fatal exception: panic_on_oops

With CONFIG_HARDENED_USERCOPY copy_to_user() checks in __check_object_size()
if the source address is within the kernel image:

 - __check_object_size() -> check_kernel_text_object():

 /* Is this address range in the kernel text area? */
 static inline const char *check_kernel_text_object(const void *ptr,
                                                    unsigned long n)
 {
         unsigned long textlow = (unsigned long)_stext;
         unsigned long texthigh = (unsigned long)_etext;
         unsigned long textlow_linear, texthigh_linear;

         if (overlaps(ptr, n, textlow, texthigh))
                 return "<kernel text>";

When the crash tool reads from 0x100000, this check leads to the kernel BUG()
in drivers/char/mem.c:

 144                 } else {
 145                         /*
 146                          * On ia64 if a page has been mapped somewhere as
 147                          * uncached, then it must also be accessed uncached
 148                          * by the kernel or data corruption may occur.
 149                          */
 150                         ptr = xlate_dev_mem_ptr(p);
 151                         if (!ptr)
 152                                 return -EFAULT;
 153 
 154                         remaining = copy_to_user(buf, ptr, sz); <<<---- BUG
 155 
 156                         unxlate_dev_mem_ptr(p, ptr);
 157                 }

Here the reporting function in mm/usercopy.c:

 61 static void report_usercopy(const void *ptr, unsigned long len,
 62                             bool to_user, const char *type)
 63 {
 64         pr_emerg("kernel memory %s attempt detected %s %p (%s) (%lu bytes)\n",
 65                 to_user ? "exposure" : "overwrite",
 66                 to_user ? "from" : "to", ptr, type ? : "unknown", len);
 67         /*
 68          * For greater effect, it would be nice to do do_group_exit(),
 69          * but BUG() actually hooks all the lock-breaking and per-arch
 70          * Oops code, so that is used here instead.
 71          */
 72         BUG();
 73 }

Shouldn't we skip the kernel address check for /dev/mem - at least when
CONFIG_STRICT_DEVMEM is not enabled?

Michael

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Does CONFIG_HARDENED_USERCOPY break /dev/mem?
  2017-11-10 15:45 Does CONFIG_HARDENED_USERCOPY break /dev/mem? Michael Holzheu
@ 2017-11-10 18:46 ` Kees Cook
  2017-11-13 10:19   ` Michael Holzheu
  0 siblings, 1 reply; 7+ messages in thread
From: Kees Cook @ 2017-11-10 18:46 UTC (permalink / raw)
  To: Michael Holzheu, Tycho Andersen
  Cc: Arnd Bergmann, Greg Kroah-Hartman, LKML, Heiko Carstens,
	Martin Schwidefsky, Vasily Gorbik

On Fri, Nov 10, 2017 at 7:45 AM, Michael Holzheu
<holzheu@linux.vnet.ibm.com> wrote:
> Hello Kees,
>
> When I try to run the crash tool on my s390 live system I get a kernel panic
> when reading memory within the kernel image:
>
>  # uname -a
>    Linux r3545011 4.14.0-rc8-00066-g1c9dbd4615fd #45 SMP PREEMPT Fri Nov 10 16:16:22 CET 2017 s390x s390x s390x GNU/Linux
>  # crash /boot/vmlinux-devel /dev/mem
>  # crash> rd 0x100000
>
>  usercopy: kernel memory exposure attempt detected from 0000000000100000 (<kernel text>) (8 bytes)
>  ------------[ cut here ]------------
>  kernel BUG at mm/usercopy.c:72!
>  illegal operation: 0001 ilc:1 [#1] PREEMPT SMP.
>  Modules linked in:
>  CPU: 0 PID: 1461 Comm: crash Not tainted 4.14.0-rc8-00066-g1c9dbd4615fd-dirty #46
>  Hardware name: IBM 2827 H66 706 (z/VM 6.3.0)
>  task: 000000001ad10100 task.stack: 000000001df78000
>  Krnl PSW : 0704d00180000000 000000000038165c (__check_object_size+0x164/0x1d0)
>             R:0 T:1 IO:1 EX:1 Key:0 M:1 W:0 P:0 AS:3 CC:1 PM:0 RI:0 EA:3
>  Krnl GPRS: 0000000012440e1d 0000000080000000 0000000000000061 00000000001cabc0
>             00000000001cc6d6 0000000000000000 0000000000cc4ed2 0000000000001000
>             000003ffc22fdd20 0000000000000008 0000000000100008 0000000000000001
>             0000000000000008 0000000000100000 0000000000381658 000000001df7bc90
>  Krnl Code: 000000000038164c: c020004a1c4a        larl    %r2,cc4ee0
>             0000000000381652: c0e5fff2581b        brasl   %r14,1cc688
>            #0000000000381658: a7f40001            brc     15,38165a
>            >000000000038165c: eb42000c000c        srlg    %r4,%r2,12
>             0000000000381662: eb32001c000c        srlg    %r3,%r2,28
>             0000000000381668: c0110003ffff        lgfi    %r1,262143
>             000000000038166e: ec31ff752065        clgrj   %r3,%r1,2,381558
>             0000000000381674: a7f4ff67            brc     15,381542
>  Call Trace:
>  ([<0000000000381658>] __check_object_size+0x160/0x1d0)
>   [<000000000082263a>] read_mem+0xaa/0x130.
>   [<0000000000386182>] __vfs_read+0x42/0x168.
>   [<000000000038632e>] vfs_read+0x86/0x140.
>   [<0000000000386a26>] SyS_read+0x66/0xc0.
>   [<0000000000ace6a4>] system_call+0xc4/0x2b0.
>  INFO: lockdep is turned off.
>  Last Breaking-Event-Address:
>   [<0000000000381658>] __check_object_size+0x160/0x1d0
>
>  Kernel panic - not syncing: Fatal exception: panic_on_oops
>
> With CONFIG_HARDENED_USERCOPY copy_to_user() checks in __check_object_size()
> if the source address is within the kernel image:
>
>  - __check_object_size() -> check_kernel_text_object():
>
>  /* Is this address range in the kernel text area? */
>  static inline const char *check_kernel_text_object(const void *ptr,
>                                                     unsigned long n)
>  {
>          unsigned long textlow = (unsigned long)_stext;
>          unsigned long texthigh = (unsigned long)_etext;
>          unsigned long textlow_linear, texthigh_linear;
>
>          if (overlaps(ptr, n, textlow, texthigh))
>                  return "<kernel text>";
>
> When the crash tool reads from 0x100000, this check leads to the kernel BUG()
> in drivers/char/mem.c:
>
>  144                 } else {
>  145                         /*
>  146                          * On ia64 if a page has been mapped somewhere as
>  147                          * uncached, then it must also be accessed uncached
>  148                          * by the kernel or data corruption may occur.
>  149                          */
>  150                         ptr = xlate_dev_mem_ptr(p);
>  151                         if (!ptr)
>  152                                 return -EFAULT;
>  153
>  154                         remaining = copy_to_user(buf, ptr, sz); <<<---- BUG
>  155
>  156                         unxlate_dev_mem_ptr(p, ptr);
>  157                 }
>
> Here the reporting function in mm/usercopy.c:
>
>  61 static void report_usercopy(const void *ptr, unsigned long len,
>  62                             bool to_user, const char *type)
>  63 {
>  64         pr_emerg("kernel memory %s attempt detected %s %p (%s) (%lu bytes)\n",
>  65                 to_user ? "exposure" : "overwrite",
>  66                 to_user ? "from" : "to", ptr, type ? : "unknown", len);
>  67         /*
>  68          * For greater effect, it would be nice to do do_group_exit(),
>  69          * but BUG() actually hooks all the lock-breaking and per-arch
>  70          * Oops code, so that is used here instead.
>  71          */
>  72         BUG();
>  73 }
>
> Shouldn't we skip the kernel address check for /dev/mem - at least when
> CONFIG_STRICT_DEVMEM is not enabled?

Some kind of better interaction is needed here, I agree. The prior
discussions around this basically resulted in declaring that
HARDENED_USERCOPY without STRICT_DEVMEM didn't make a lot of sense.
i.e. HARDENED_USERCOPY should maybe require STRICT_DEVMEM, etc. Tycho
wrote this up after some back-and-forth:

https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/commit/?h=kspp/kconfig&id=ae98b44ceb338ae165a7f18f29f6244893712da3

In the end, I was still uncomfortable with it because the usercopy
protection is wider than just the kernel text, so it seemed strange to
force it off when not using STRICT_DEVMEM.

What's the use-case here where you've got hardened usercopy without
strict devmem? Normally I'd expect any system built with secure
configurations to want strict devmem.

-Kees

-- 
Kees Cook
Pixel Security

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Does CONFIG_HARDENED_USERCOPY break /dev/mem?
  2017-11-10 18:46 ` Kees Cook
@ 2017-11-13 10:19   ` Michael Holzheu
  2017-11-22  9:28     ` Michael Holzheu
  0 siblings, 1 reply; 7+ messages in thread
From: Michael Holzheu @ 2017-11-13 10:19 UTC (permalink / raw)
  To: Kees Cook
  Cc: Tycho Andersen, Arnd Bergmann, Greg Kroah-Hartman, LKML,
	Heiko Carstens, Martin Schwidefsky, Vasily Gorbik

Am Fri, 10 Nov 2017 10:46:49 -0800
schrieb Kees Cook <keescook@chromium.org>:

> On Fri, Nov 10, 2017 at 7:45 AM, Michael Holzheu
> <holzheu@linux.vnet.ibm.com> wrote:
> > Hello Kees,
> >
> > When I try to run the crash tool on my s390 live system I get a kernel panic
> > when reading memory within the kernel image:
> >
> >  # uname -a
> >    Linux r3545011 4.14.0-rc8-00066-g1c9dbd4615fd #45 SMP PREEMPT Fri Nov 10 16:16:22 CET 2017 s390x s390x s390x GNU/Linux
> >  # crash /boot/vmlinux-devel /dev/mem
> >  # crash> rd 0x100000
> >
> >  usercopy: kernel memory exposure attempt detected from 0000000000100000 (<kernel text>) (8 bytes)
> >  ------------[ cut here ]------------
> >  kernel BUG at mm/usercopy.c:72!
> >  illegal operation: 0001 ilc:1 [#1] PREEMPT SMP.
> >  Modules linked in:
> >  CPU: 0 PID: 1461 Comm: crash Not tainted 4.14.0-rc8-00066-g1c9dbd4615fd-dirty #46
> >  Hardware name: IBM 2827 H66 706 (z/VM 6.3.0)
> >  task: 000000001ad10100 task.stack: 000000001df78000
> >  Krnl PSW : 0704d00180000000 000000000038165c (__check_object_size+0x164/0x1d0)
> >             R:0 T:1 IO:1 EX:1 Key:0 M:1 W:0 P:0 AS:3 CC:1 PM:0 RI:0 EA:3
> >  Krnl GPRS: 0000000012440e1d 0000000080000000 0000000000000061 00000000001cabc0
> >             00000000001cc6d6 0000000000000000 0000000000cc4ed2 0000000000001000
> >             000003ffc22fdd20 0000000000000008 0000000000100008 0000000000000001
> >             0000000000000008 0000000000100000 0000000000381658 000000001df7bc90
> >  Krnl Code: 000000000038164c: c020004a1c4a        larl    %r2,cc4ee0
> >             0000000000381652: c0e5fff2581b        brasl   %r14,1cc688
> >            #0000000000381658: a7f40001            brc     15,38165a
> >            >000000000038165c: eb42000c000c        srlg    %r4,%r2,12
> >             0000000000381662: eb32001c000c        srlg    %r3,%r2,28
> >             0000000000381668: c0110003ffff        lgfi    %r1,262143
> >             000000000038166e: ec31ff752065        clgrj   %r3,%r1,2,381558
> >             0000000000381674: a7f4ff67            brc     15,381542
> >  Call Trace:
> >  ([<0000000000381658>] __check_object_size+0x160/0x1d0)
> >   [<000000000082263a>] read_mem+0xaa/0x130.
> >   [<0000000000386182>] __vfs_read+0x42/0x168.
> >   [<000000000038632e>] vfs_read+0x86/0x140.
> >   [<0000000000386a26>] SyS_read+0x66/0xc0.
> >   [<0000000000ace6a4>] system_call+0xc4/0x2b0.
> >  INFO: lockdep is turned off.
> >  Last Breaking-Event-Address:
> >   [<0000000000381658>] __check_object_size+0x160/0x1d0
> >
> >  Kernel panic - not syncing: Fatal exception: panic_on_oops
> >
> > With CONFIG_HARDENED_USERCOPY copy_to_user() checks in __check_object_size()
> > if the source address is within the kernel image:
> >
> >  - __check_object_size() -> check_kernel_text_object():
> >
> >  /* Is this address range in the kernel text area? */
> >  static inline const char *check_kernel_text_object(const void *ptr,
> >                                                     unsigned long n)
> >  {
> >          unsigned long textlow = (unsigned long)_stext;
> >          unsigned long texthigh = (unsigned long)_etext;
> >          unsigned long textlow_linear, texthigh_linear;
> >
> >          if (overlaps(ptr, n, textlow, texthigh))
> >                  return "<kernel text>";
> >
> > When the crash tool reads from 0x100000, this check leads to the kernel BUG()
> > in drivers/char/mem.c:
> >
> >  144                 } else {
> >  145                         /*
> >  146                          * On ia64 if a page has been mapped somewhere as
> >  147                          * uncached, then it must also be accessed uncached
> >  148                          * by the kernel or data corruption may occur.
> >  149                          */
> >  150                         ptr = xlate_dev_mem_ptr(p);
> >  151                         if (!ptr)
> >  152                                 return -EFAULT;
> >  153
> >  154                         remaining = copy_to_user(buf, ptr, sz); <<<---- BUG
> >  155
> >  156                         unxlate_dev_mem_ptr(p, ptr);
> >  157                 }
> >
> > Here the reporting function in mm/usercopy.c:
> >
> >  61 static void report_usercopy(const void *ptr, unsigned long len,
> >  62                             bool to_user, const char *type)
> >  63 {
> >  64         pr_emerg("kernel memory %s attempt detected %s %p (%s) (%lu bytes)\n",
> >  65                 to_user ? "exposure" : "overwrite",
> >  66                 to_user ? "from" : "to", ptr, type ? : "unknown", len);
> >  67         /*
> >  68          * For greater effect, it would be nice to do do_group_exit(),
> >  69          * but BUG() actually hooks all the lock-breaking and per-arch
> >  70          * Oops code, so that is used here instead.
> >  71          */
> >  72         BUG();
> >  73 }
> >
> > Shouldn't we skip the kernel address check for /dev/mem - at least when
> > CONFIG_STRICT_DEVMEM is not enabled?
> 
> Some kind of better interaction is needed here, I agree. The prior
> discussions around this basically resulted in declaring that
> HARDENED_USERCOPY without STRICT_DEVMEM didn't make a lot of sense.
> i.e. HARDENED_USERCOPY should maybe require STRICT_DEVMEM, etc. Tycho
> wrote this up after some back-and-forth:
> 
> https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/commit/?h=kspp/kconfig&id=ae98b44ceb338ae165a7f18f29f6244893712da3
> 
> In the end, I was still uncomfortable with it because the usercopy
> protection is wider than just the kernel text, so it seemed strange to
> force it off when not using STRICT_DEVMEM.
> 
> What's the use-case here where you've got hardened usercopy without
> strict devmem?

We use that configuration for development and test. We disabled STRICT_DEVMEM
for debugging the live system with crash. We enabled HARDENED_USERCOPY for
finding user-copy bugs.

Michael

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Does CONFIG_HARDENED_USERCOPY break /dev/mem?
  2017-11-13 10:19   ` Michael Holzheu
@ 2017-11-22  9:28     ` Michael Holzheu
  2017-11-22 17:43       ` Kees Cook
  0 siblings, 1 reply; 7+ messages in thread
From: Michael Holzheu @ 2017-11-22  9:28 UTC (permalink / raw)
  To: Kees Cook
  Cc: Michael Holzheu, Tycho Andersen, Arnd Bergmann,
	Greg Kroah-Hartman, LKML, Heiko Carstens, Martin Schwidefsky,
	Vasily Gorbik

Am Mon, 13 Nov 2017 11:19:38 +0100
schrieb Michael Holzheu <holzheu@linux.vnet.ibm.com>:

> Am Fri, 10 Nov 2017 10:46:49 -0800
> schrieb Kees Cook <keescook@chromium.org>:
> 
> > On Fri, Nov 10, 2017 at 7:45 AM, Michael Holzheu
> > <holzheu@linux.vnet.ibm.com> wrote:
> > > Hello Kees,
> > >
> > > When I try to run the crash tool on my s390 live system I get a kernel panic
> > > when reading memory within the kernel image:
> > >
> > >  # uname -a
> > >    Linux r3545011 4.14.0-rc8-00066-g1c9dbd4615fd #45 SMP PREEMPT Fri Nov 10 16:16:22 CET 2017 s390x s390x s390x GNU/Linux
> > >  # crash /boot/vmlinux-devel /dev/mem
> > >  # crash> rd 0x100000
> > >
> > >  usercopy: kernel memory exposure attempt detected from 0000000000100000 (<kernel text>) (8 bytes)
> > >  ------------[ cut here ]------------
> > >  kernel BUG at mm/usercopy.c:72!
> > >  illegal operation: 0001 ilc:1 [#1] PREEMPT SMP.
> > >  Modules linked in:
> > >  CPU: 0 PID: 1461 Comm: crash Not tainted 4.14.0-rc8-00066-g1c9dbd4615fd-dirty #46
> > >  Hardware name: IBM 2827 H66 706 (z/VM 6.3.0)
> > >  task: 000000001ad10100 task.stack: 000000001df78000
> > >  Krnl PSW : 0704d00180000000 000000000038165c (__check_object_size+0x164/0x1d0)
> > >             R:0 T:1 IO:1 EX:1 Key:0 M:1 W:0 P:0 AS:3 CC:1 PM:0 RI:0 EA:3
> > >  Krnl GPRS: 0000000012440e1d 0000000080000000 0000000000000061 00000000001cabc0
> > >             00000000001cc6d6 0000000000000000 0000000000cc4ed2 0000000000001000
> > >             000003ffc22fdd20 0000000000000008 0000000000100008 0000000000000001
> > >             0000000000000008 0000000000100000 0000000000381658 000000001df7bc90
> > >  Krnl Code: 000000000038164c: c020004a1c4a        larl    %r2,cc4ee0
> > >             0000000000381652: c0e5fff2581b        brasl   %r14,1cc688
> > >            #0000000000381658: a7f40001            brc     15,38165a
> > >            >000000000038165c: eb42000c000c        srlg    %r4,%r2,12
> > >             0000000000381662: eb32001c000c        srlg    %r3,%r2,28
> > >             0000000000381668: c0110003ffff        lgfi    %r1,262143
> > >             000000000038166e: ec31ff752065        clgrj   %r3,%r1,2,381558
> > >             0000000000381674: a7f4ff67            brc     15,381542
> > >  Call Trace:
> > >  ([<0000000000381658>] __check_object_size+0x160/0x1d0)
> > >   [<000000000082263a>] read_mem+0xaa/0x130.
> > >   [<0000000000386182>] __vfs_read+0x42/0x168.
> > >   [<000000000038632e>] vfs_read+0x86/0x140.
> > >   [<0000000000386a26>] SyS_read+0x66/0xc0.
> > >   [<0000000000ace6a4>] system_call+0xc4/0x2b0.
> > >  INFO: lockdep is turned off.
> > >  Last Breaking-Event-Address:
> > >   [<0000000000381658>] __check_object_size+0x160/0x1d0
> > >
> > >  Kernel panic - not syncing: Fatal exception: panic_on_oops
> > >
> > > With CONFIG_HARDENED_USERCOPY copy_to_user() checks in __check_object_size()
> > > if the source address is within the kernel image:
> > >
> > >  - __check_object_size() -> check_kernel_text_object():
> > >
> > >  /* Is this address range in the kernel text area? */
> > >  static inline const char *check_kernel_text_object(const void *ptr,
> > >                                                     unsigned long n)
> > >  {
> > >          unsigned long textlow = (unsigned long)_stext;
> > >          unsigned long texthigh = (unsigned long)_etext;
> > >          unsigned long textlow_linear, texthigh_linear;
> > >
> > >          if (overlaps(ptr, n, textlow, texthigh))
> > >                  return "<kernel text>";
> > >
> > > When the crash tool reads from 0x100000, this check leads to the kernel BUG()
> > > in drivers/char/mem.c:
> > >
> > >  144                 } else {
> > >  145                         /*
> > >  146                          * On ia64 if a page has been mapped somewhere as
> > >  147                          * uncached, then it must also be accessed uncached
> > >  148                          * by the kernel or data corruption may occur.
> > >  149                          */
> > >  150                         ptr = xlate_dev_mem_ptr(p);
> > >  151                         if (!ptr)
> > >  152                                 return -EFAULT;
> > >  153
> > >  154                         remaining = copy_to_user(buf, ptr, sz); <<<---- BUG
> > >  155
> > >  156                         unxlate_dev_mem_ptr(p, ptr);
> > >  157                 }
> > >
> > > Here the reporting function in mm/usercopy.c:
> > >
> > >  61 static void report_usercopy(const void *ptr, unsigned long len,
> > >  62                             bool to_user, const char *type)
> > >  63 {
> > >  64         pr_emerg("kernel memory %s attempt detected %s %p (%s) (%lu bytes)\n",
> > >  65                 to_user ? "exposure" : "overwrite",
> > >  66                 to_user ? "from" : "to", ptr, type ? : "unknown", len);
> > >  67         /*
> > >  68          * For greater effect, it would be nice to do do_group_exit(),
> > >  69          * but BUG() actually hooks all the lock-breaking and per-arch
> > >  70          * Oops code, so that is used here instead.
> > >  71          */
> > >  72         BUG();
> > >  73 }
> > >
> > > Shouldn't we skip the kernel address check for /dev/mem - at least when
> > > CONFIG_STRICT_DEVMEM is not enabled?
> > 
> > Some kind of better interaction is needed here, I agree. The prior
> > discussions around this basically resulted in declaring that
> > HARDENED_USERCOPY without STRICT_DEVMEM didn't make a lot of sense.
> > i.e. HARDENED_USERCOPY should maybe require STRICT_DEVMEM, etc. Tycho
> > wrote this up after some back-and-forth:
> > 
> > https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/commit/?h=kspp/kconfig&id=ae98b44ceb338ae165a7f18f29f6244893712da3
> > 
> > In the end, I was still uncomfortable with it because the usercopy
> > protection is wider than just the kernel text, so it seemed strange to
> > force it off when not using STRICT_DEVMEM.
> > 
> > What's the use-case here where you've got hardened usercopy without
> > strict devmem?
> 
> We use that configuration for development and test. We disabled STRICT_DEVMEM
> for debugging the live system with crash. We enabled HARDENED_USERCOPY for
> finding user-copy bugs.

So what's your plan now? How will you fix this issue?

Michael

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Does CONFIG_HARDENED_USERCOPY break /dev/mem?
  2017-11-22  9:28     ` Michael Holzheu
@ 2017-11-22 17:43       ` Kees Cook
  2017-11-22 17:56         ` Kees Cook
  2017-11-23 16:08         ` Michael Holzheu
  0 siblings, 2 replies; 7+ messages in thread
From: Kees Cook @ 2017-11-22 17:43 UTC (permalink / raw)
  To: Michael Holzheu
  Cc: Tycho Andersen, Arnd Bergmann, Greg Kroah-Hartman, LKML,
	Heiko Carstens, Martin Schwidefsky, Vasily Gorbik

On Wed, Nov 22, 2017 at 1:28 AM, Michael Holzheu
<holzheu@linux.vnet.ibm.com> wrote:
> Am Mon, 13 Nov 2017 11:19:38 +0100
> schrieb Michael Holzheu <holzheu@linux.vnet.ibm.com>:
>
>> Am Fri, 10 Nov 2017 10:46:49 -0800
>> schrieb Kees Cook <keescook@chromium.org>:
>>
>> > On Fri, Nov 10, 2017 at 7:45 AM, Michael Holzheu
>> > <holzheu@linux.vnet.ibm.com> wrote:
>> > > Hello Kees,
>> > >
>> > > When I try to run the crash tool on my s390 live system I get a kernel panic
>> > > when reading memory within the kernel image:
>> > >
>> > >  # uname -a
>> > >    Linux r3545011 4.14.0-rc8-00066-g1c9dbd4615fd #45 SMP PREEMPT Fri Nov 10 16:16:22 CET 2017 s390x s390x s390x GNU/Linux
>> > >  # crash /boot/vmlinux-devel /dev/mem
>> > >  # crash> rd 0x100000
>> > >
>> > >  usercopy: kernel memory exposure attempt detected from 0000000000100000 (<kernel text>) (8 bytes)
>> > >  ------------[ cut here ]------------
>> > >  kernel BUG at mm/usercopy.c:72!
>> > >  illegal operation: 0001 ilc:1 [#1] PREEMPT SMP.
>> > >  Modules linked in:
>> > >  CPU: 0 PID: 1461 Comm: crash Not tainted 4.14.0-rc8-00066-g1c9dbd4615fd-dirty #46
>> > >  Hardware name: IBM 2827 H66 706 (z/VM 6.3.0)
>> > >  task: 000000001ad10100 task.stack: 000000001df78000
>> > >  Krnl PSW : 0704d00180000000 000000000038165c (__check_object_size+0x164/0x1d0)
>> > >             R:0 T:1 IO:1 EX:1 Key:0 M:1 W:0 P:0 AS:3 CC:1 PM:0 RI:0 EA:3
>> > >  Krnl GPRS: 0000000012440e1d 0000000080000000 0000000000000061 00000000001cabc0
>> > >             00000000001cc6d6 0000000000000000 0000000000cc4ed2 0000000000001000
>> > >             000003ffc22fdd20 0000000000000008 0000000000100008 0000000000000001
>> > >             0000000000000008 0000000000100000 0000000000381658 000000001df7bc90
>> > >  Krnl Code: 000000000038164c: c020004a1c4a        larl    %r2,cc4ee0
>> > >             0000000000381652: c0e5fff2581b        brasl   %r14,1cc688
>> > >            #0000000000381658: a7f40001            brc     15,38165a
>> > >            >000000000038165c: eb42000c000c        srlg    %r4,%r2,12
>> > >             0000000000381662: eb32001c000c        srlg    %r3,%r2,28
>> > >             0000000000381668: c0110003ffff        lgfi    %r1,262143
>> > >             000000000038166e: ec31ff752065        clgrj   %r3,%r1,2,381558
>> > >             0000000000381674: a7f4ff67            brc     15,381542
>> > >  Call Trace:
>> > >  ([<0000000000381658>] __check_object_size+0x160/0x1d0)
>> > >   [<000000000082263a>] read_mem+0xaa/0x130.
>> > >   [<0000000000386182>] __vfs_read+0x42/0x168.
>> > >   [<000000000038632e>] vfs_read+0x86/0x140.
>> > >   [<0000000000386a26>] SyS_read+0x66/0xc0.
>> > >   [<0000000000ace6a4>] system_call+0xc4/0x2b0.
>> > >  INFO: lockdep is turned off.
>> > >  Last Breaking-Event-Address:
>> > >   [<0000000000381658>] __check_object_size+0x160/0x1d0
>> > >
>> > >  Kernel panic - not syncing: Fatal exception: panic_on_oops
>> > >
>> > > With CONFIG_HARDENED_USERCOPY copy_to_user() checks in __check_object_size()
>> > > if the source address is within the kernel image:
>> > >
>> > >  - __check_object_size() -> check_kernel_text_object():
>> > >
>> > >  /* Is this address range in the kernel text area? */
>> > >  static inline const char *check_kernel_text_object(const void *ptr,
>> > >                                                     unsigned long n)
>> > >  {
>> > >          unsigned long textlow = (unsigned long)_stext;
>> > >          unsigned long texthigh = (unsigned long)_etext;
>> > >          unsigned long textlow_linear, texthigh_linear;
>> > >
>> > >          if (overlaps(ptr, n, textlow, texthigh))
>> > >                  return "<kernel text>";
>> > >
>> > > When the crash tool reads from 0x100000, this check leads to the kernel BUG()
>> > > in drivers/char/mem.c:
>> > >
>> > >  144                 } else {
>> > >  145                         /*
>> > >  146                          * On ia64 if a page has been mapped somewhere as
>> > >  147                          * uncached, then it must also be accessed uncached
>> > >  148                          * by the kernel or data corruption may occur.
>> > >  149                          */
>> > >  150                         ptr = xlate_dev_mem_ptr(p);
>> > >  151                         if (!ptr)
>> > >  152                                 return -EFAULT;
>> > >  153
>> > >  154                         remaining = copy_to_user(buf, ptr, sz); <<<---- BUG
>> > >  155
>> > >  156                         unxlate_dev_mem_ptr(p, ptr);
>> > >  157                 }
>> > >
>> > > Here the reporting function in mm/usercopy.c:
>> > >
>> > >  61 static void report_usercopy(const void *ptr, unsigned long len,
>> > >  62                             bool to_user, const char *type)
>> > >  63 {
>> > >  64         pr_emerg("kernel memory %s attempt detected %s %p (%s) (%lu bytes)\n",
>> > >  65                 to_user ? "exposure" : "overwrite",
>> > >  66                 to_user ? "from" : "to", ptr, type ? : "unknown", len);
>> > >  67         /*
>> > >  68          * For greater effect, it would be nice to do do_group_exit(),
>> > >  69          * but BUG() actually hooks all the lock-breaking and per-arch
>> > >  70          * Oops code, so that is used here instead.
>> > >  71          */
>> > >  72         BUG();
>> > >  73 }
>> > >
>> > > Shouldn't we skip the kernel address check for /dev/mem - at least when
>> > > CONFIG_STRICT_DEVMEM is not enabled?
>> >
>> > Some kind of better interaction is needed here, I agree. The prior
>> > discussions around this basically resulted in declaring that
>> > HARDENED_USERCOPY without STRICT_DEVMEM didn't make a lot of sense.
>> > i.e. HARDENED_USERCOPY should maybe require STRICT_DEVMEM, etc. Tycho
>> > wrote this up after some back-and-forth:
>> >
>> > https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/commit/?h=kspp/kconfig&id=ae98b44ceb338ae165a7f18f29f6244893712da3
>> >
>> > In the end, I was still uncomfortable with it because the usercopy
>> > protection is wider than just the kernel text, so it seemed strange to
>> > force it off when not using STRICT_DEVMEM.
>> >
>> > What's the use-case here where you've got hardened usercopy without
>> > strict devmem?
>>
>> We use that configuration for development and test. We disabled STRICT_DEVMEM
>> for debugging the live system with crash. We enabled HARDENED_USERCOPY for
>> finding user-copy bugs.
>
> So what's your plan now? How will you fix this issue?

I think the best plan here would be to use the Kconfig "imply
STRICT_DEVMEM" in HARDENED_USERCOPY. That would make STRICT_DEVMEM
enabled by default but still configurable. Then the kernel-text check
in hardened usercopy could be skip when !STRICT_DEVMEM.

My primary concern is with failing closed. If someone is only paying
attention to choosing HARDENED_USERCOPY, it should not be possible to
read out kernel memory unless they specifically try to unset something
else (in this case, STRICT_DEVMEM).

How does that sound?

-Kees

-- 
Kees Cook
Pixel Security

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Does CONFIG_HARDENED_USERCOPY break /dev/mem?
  2017-11-22 17:43       ` Kees Cook
@ 2017-11-22 17:56         ` Kees Cook
  2017-11-23 16:08         ` Michael Holzheu
  1 sibling, 0 replies; 7+ messages in thread
From: Kees Cook @ 2017-11-22 17:56 UTC (permalink / raw)
  To: Michael Holzheu
  Cc: Tycho Andersen, Arnd Bergmann, Greg Kroah-Hartman, LKML,
	Heiko Carstens, Martin Schwidefsky, Vasily Gorbik

On Wed, Nov 22, 2017 at 9:43 AM, Kees Cook <keescook@chromium.org> wrote:
> On Wed, Nov 22, 2017 at 1:28 AM, Michael Holzheu
> <holzheu@linux.vnet.ibm.com> wrote:
>> So what's your plan now? How will you fix this issue?
>
> I think the best plan here would be to use the Kconfig "imply
> STRICT_DEVMEM" in HARDENED_USERCOPY. That would make STRICT_DEVMEM
> enabled by default but still configurable. Then the kernel-text check
> in hardened usercopy could be skip when !STRICT_DEVMEM.

Hmm, this doesn't work the way I was expecting...

diff --git a/security/Kconfig b/security/Kconfig
index e8e449444e65..3b4effd8bbc2 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -143,6 +143,7 @@ config HARDENED_USERCOPY
        bool "Harden memory copies between kernel and userspace"
        depends on HAVE_HARDENED_USERCOPY_ALLOCATOR
        select BUG
+       imply STRICT_DEVMEM
        help
          This option checks for obviously wrong memory regions when
          copying memory to/from the kernel (via copy_to_user() and

$ make defconfig
$ egrep '(DEVMEM|HARDENED_USERCOPY)\b' .config
CONFIG_DEVMEM=y
# CONFIG_STRICT_DEVMEM is not set
# CONFIG_HARDENED_USERCOPY is not set
$ ./scripts/config -e CONFIG_HARDENED_USERCOPY
$ egrep '(DEVMEM|HARDENED_USERCOPY)\b' .config
CONFIG_DEVMEM=y
# CONFIG_STRICT_DEVMEM is not set
CONFIG_HARDENED_USERCOPY=y

Maybe make STRICT_DEVMEM's default tie to HARDENED_USERCOPY? Bleh,
this doesn't seem to work either:

diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 947d3e2ed5c2..8cc05033ba65 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1985,7 +1985,7 @@ config STRICT_DEVMEM
        bool "Filter access to /dev/mem"
        depends on MMU && DEVMEM
        depends on ARCH_HAS_DEVMEM_IS_ALLOWED
-       default y if TILE || PPC
+       default y if TILE || PPC || HARDENED_USERCOPY
        ---help---
          If this option is disabled, you allow userspace (root) access to all
          of memory, including kernel and userspace memory. Accidental

I'm open to suggestions...

-Kees

-- 
Kees Cook
Pixel Security

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: Does CONFIG_HARDENED_USERCOPY break /dev/mem?
  2017-11-22 17:43       ` Kees Cook
  2017-11-22 17:56         ` Kees Cook
@ 2017-11-23 16:08         ` Michael Holzheu
  1 sibling, 0 replies; 7+ messages in thread
From: Michael Holzheu @ 2017-11-23 16:08 UTC (permalink / raw)
  To: Kees Cook
  Cc: Tycho Andersen, Arnd Bergmann, Greg Kroah-Hartman, LKML,
	Heiko Carstens, Martin Schwidefsky, Vasily Gorbik

Am Wed, 22 Nov 2017 09:43:19 -0800
schrieb Kees Cook <keescook@chromium.org>:

> On Wed, Nov 22, 2017 at 1:28 AM, Michael Holzheu
> <holzheu@linux.vnet.ibm.com> wrote:
> > Am Mon, 13 Nov 2017 11:19:38 +0100
> > schrieb Michael Holzheu <holzheu@linux.vnet.ibm.com>:
> >
> >> Am Fri, 10 Nov 2017 10:46:49 -0800
> >> schrieb Kees Cook <keescook@chromium.org>:
> >>
> >> > On Fri, Nov 10, 2017 at 7:45 AM, Michael Holzheu
> >> > <holzheu@linux.vnet.ibm.com> wrote:
> >> > > Hello Kees,
> >> > >
> >> > > When I try to run the crash tool on my s390 live system I get a kernel panic
> >> > > when reading memory within the kernel image:
> >> > >
> >> > >  # uname -a
> >> > >    Linux r3545011 4.14.0-rc8-00066-g1c9dbd4615fd #45 SMP PREEMPT Fri Nov 10 16:16:22 CET 2017 s390x s390x s390x GNU/Linux
> >> > >  # crash /boot/vmlinux-devel /dev/mem
> >> > >  # crash> rd 0x100000
> >> > >
> >> > >  usercopy: kernel memory exposure attempt detected from 0000000000100000 (<kernel text>) (8 bytes)
> >> > >  ------------[ cut here ]------------
> >> > >  kernel BUG at mm/usercopy.c:72!
> >> > >  illegal operation: 0001 ilc:1 [#1] PREEMPT SMP.
> >> > >  Modules linked in:
> >> > >  CPU: 0 PID: 1461 Comm: crash Not tainted 4.14.0-rc8-00066-g1c9dbd4615fd-dirty #46
> >> > >  Hardware name: IBM 2827 H66 706 (z/VM 6.3.0)
> >> > >  task: 000000001ad10100 task.stack: 000000001df78000
> >> > >  Krnl PSW : 0704d00180000000 000000000038165c (__check_object_size+0x164/0x1d0)
> >> > >             R:0 T:1 IO:1 EX:1 Key:0 M:1 W:0 P:0 AS:3 CC:1 PM:0 RI:0 EA:3
> >> > >  Krnl GPRS: 0000000012440e1d 0000000080000000 0000000000000061 00000000001cabc0
> >> > >             00000000001cc6d6 0000000000000000 0000000000cc4ed2 0000000000001000
> >> > >             000003ffc22fdd20 0000000000000008 0000000000100008 0000000000000001
> >> > >             0000000000000008 0000000000100000 0000000000381658 000000001df7bc90
> >> > >  Krnl Code: 000000000038164c: c020004a1c4a        larl    %r2,cc4ee0
> >> > >             0000000000381652: c0e5fff2581b        brasl   %r14,1cc688
> >> > >            #0000000000381658: a7f40001            brc     15,38165a
> >> > >            >000000000038165c: eb42000c000c        srlg    %r4,%r2,12
> >> > >             0000000000381662: eb32001c000c        srlg    %r3,%r2,28
> >> > >             0000000000381668: c0110003ffff        lgfi    %r1,262143
> >> > >             000000000038166e: ec31ff752065        clgrj   %r3,%r1,2,381558
> >> > >             0000000000381674: a7f4ff67            brc     15,381542
> >> > >  Call Trace:
> >> > >  ([<0000000000381658>] __check_object_size+0x160/0x1d0)
> >> > >   [<000000000082263a>] read_mem+0xaa/0x130.
> >> > >   [<0000000000386182>] __vfs_read+0x42/0x168.
> >> > >   [<000000000038632e>] vfs_read+0x86/0x140.
> >> > >   [<0000000000386a26>] SyS_read+0x66/0xc0.
> >> > >   [<0000000000ace6a4>] system_call+0xc4/0x2b0.
> >> > >  INFO: lockdep is turned off.
> >> > >  Last Breaking-Event-Address:
> >> > >   [<0000000000381658>] __check_object_size+0x160/0x1d0
> >> > >
> >> > >  Kernel panic - not syncing: Fatal exception: panic_on_oops
> >> > >
> >> > > With CONFIG_HARDENED_USERCOPY copy_to_user() checks in __check_object_size()
> >> > > if the source address is within the kernel image:
> >> > >
> >> > >  - __check_object_size() -> check_kernel_text_object():
> >> > >
> >> > >  /* Is this address range in the kernel text area? */
> >> > >  static inline const char *check_kernel_text_object(const void *ptr,
> >> > >                                                     unsigned long n)
> >> > >  {
> >> > >          unsigned long textlow = (unsigned long)_stext;
> >> > >          unsigned long texthigh = (unsigned long)_etext;
> >> > >          unsigned long textlow_linear, texthigh_linear;
> >> > >
> >> > >          if (overlaps(ptr, n, textlow, texthigh))
> >> > >                  return "<kernel text>";
> >> > >
> >> > > When the crash tool reads from 0x100000, this check leads to the kernel BUG()
> >> > > in drivers/char/mem.c:
> >> > >
> >> > >  144                 } else {
> >> > >  145                         /*
> >> > >  146                          * On ia64 if a page has been mapped somewhere as
> >> > >  147                          * uncached, then it must also be accessed uncached
> >> > >  148                          * by the kernel or data corruption may occur.
> >> > >  149                          */
> >> > >  150                         ptr = xlate_dev_mem_ptr(p);
> >> > >  151                         if (!ptr)
> >> > >  152                                 return -EFAULT;
> >> > >  153
> >> > >  154                         remaining = copy_to_user(buf, ptr, sz); <<<---- BUG
> >> > >  155
> >> > >  156                         unxlate_dev_mem_ptr(p, ptr);
> >> > >  157                 }
> >> > >
> >> > > Here the reporting function in mm/usercopy.c:
> >> > >
> >> > >  61 static void report_usercopy(const void *ptr, unsigned long len,
> >> > >  62                             bool to_user, const char *type)
> >> > >  63 {
> >> > >  64         pr_emerg("kernel memory %s attempt detected %s %p (%s) (%lu bytes)\n",
> >> > >  65                 to_user ? "exposure" : "overwrite",
> >> > >  66                 to_user ? "from" : "to", ptr, type ? : "unknown", len);
> >> > >  67         /*
> >> > >  68          * For greater effect, it would be nice to do do_group_exit(),
> >> > >  69          * but BUG() actually hooks all the lock-breaking and per-arch
> >> > >  70          * Oops code, so that is used here instead.
> >> > >  71          */
> >> > >  72         BUG();
> >> > >  73 }
> >> > >
> >> > > Shouldn't we skip the kernel address check for /dev/mem - at least when
> >> > > CONFIG_STRICT_DEVMEM is not enabled?
> >> >
> >> > Some kind of better interaction is needed here, I agree. The prior
> >> > discussions around this basically resulted in declaring that
> >> > HARDENED_USERCOPY without STRICT_DEVMEM didn't make a lot of sense.
> >> > i.e. HARDENED_USERCOPY should maybe require STRICT_DEVMEM, etc. Tycho
> >> > wrote this up after some back-and-forth:
> >> >
> >> > https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/commit/?h=kspp/kconfig&id=ae98b44ceb338ae165a7f18f29f6244893712da3
> >> >
> >> > In the end, I was still uncomfortable with it because the usercopy
> >> > protection is wider than just the kernel text, so it seemed strange to
> >> > force it off when not using STRICT_DEVMEM.
> >> >
> >> > What's the use-case here where you've got hardened usercopy without
> >> > strict devmem?
> >>
> >> We use that configuration for development and test. We disabled STRICT_DEVMEM
> >> for debugging the live system with crash. We enabled HARDENED_USERCOPY for
> >> finding user-copy bugs.
> >
> > So what's your plan now? How will you fix this issue?
> 
> I think the best plan here would be to use the Kconfig "imply
> STRICT_DEVMEM" in HARDENED_USERCOPY. That would make STRICT_DEVMEM
> enabled by default but still configurable. Then the kernel-text check
> in hardened usercopy could be skip when !STRICT_DEVMEM.
> 
> My primary concern is with failing closed. If someone is only paying
> attention to choosing HARDENED_USERCOPY, it should not be possible to
> read out kernel memory unless they specifically try to unset something
> else (in this case, STRICT_DEVMEM).
> 
> How does that sound?

Looks ok to me.

Michael

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2017-11-23 16:08 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-10 15:45 Does CONFIG_HARDENED_USERCOPY break /dev/mem? Michael Holzheu
2017-11-10 18:46 ` Kees Cook
2017-11-13 10:19   ` Michael Holzheu
2017-11-22  9:28     ` Michael Holzheu
2017-11-22 17:43       ` Kees Cook
2017-11-22 17:56         ` Kees Cook
2017-11-23 16:08         ` Michael Holzheu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).