diff mbox

[v3] drivers/char: kmem: disable on arm64

Message ID 1497941940-2699-1-git-send-email-ard.biesheuvel@linaro.org (mailing list archive)
State New, archived
Headers show

Commit Message

Ard Biesheuvel June 20, 2017, 6:59 a.m. UTC
As it turns out, arm64 deviates from other architectures in the way it
maps the VMALLOC region: on most (all?) other architectures, it resides
strictly above the kernel's direct mapping of DRAM, but on arm64, this
is the other way around. For instance, for a 48-bit VA configuration,
we have

  modules : 0xffff000000000000 - 0xffff000008000000   (   128 MB)
  vmalloc : 0xffff000008000000 - 0xffff7dffbfff0000   (129022 GB)
  ...
  vmemmap : 0xffff7e0000000000 - 0xffff800000000000   (  2048 GB maximum)
            0xffff7e0000000000 - 0xffff7e0003ff0000   (    63 MB actual)
  memory  : 0xffff800000000000 - 0xffff8000ffc00000   (  4092 MB)

This has mostly gone unnoticed until now, but it does appear that it
breaks an assumption in the kcore read/write code, which does something
like

  if (p < (unsigned long) high_memory) {
    ... use straight copy_[to|from]_user() using p as virtual address ...
  }
  ...
  if (count > 0) {
    ... use vread/vwrite for accesses past high_memory ...
  }

The first condition will inadvertently hold for the VMALLOC region if
VMALLOC_START < PAGE_OFFSET [which is the case on arm64], but the read
or write will subsequently fail the virt_addr_valid() check, resulting
in a -ENXIO return value.

Given how kmem seems to be living in borrowed time anyway, and given
the fact that nobody noticed that the read/write interface is broken
on arm64 in the first place, let's not bother trying to fix it, but
simply disable the /dev/kmem interface entirely for arm64.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
v3: improve commit log
v2: disable /dev/kmem entirely rather than bandaiding it

 drivers/char/Kconfig | 2 ++
 1 file changed, 2 insertions(+)

Comments

Mark Rutland June 20, 2017, 9:31 a.m. UTC | #1
On Tue, Jun 20, 2017 at 08:59:00AM +0200, Ard Biesheuvel wrote:
> As it turns out, arm64 deviates from other architectures in the way it
> maps the VMALLOC region: on most (all?) other architectures, it resides
> strictly above the kernel's direct mapping of DRAM, but on arm64, this
> is the other way around. For instance, for a 48-bit VA configuration,
> we have
> 
>   modules : 0xffff000000000000 - 0xffff000008000000   (   128 MB)
>   vmalloc : 0xffff000008000000 - 0xffff7dffbfff0000   (129022 GB)
>   ...
>   vmemmap : 0xffff7e0000000000 - 0xffff800000000000   (  2048 GB maximum)
>             0xffff7e0000000000 - 0xffff7e0003ff0000   (    63 MB actual)
>   memory  : 0xffff800000000000 - 0xffff8000ffc00000   (  4092 MB)
> 
> This has mostly gone unnoticed until now, but it does appear that it
> breaks an assumption in the kcore read/write code, which does something
> like
> 
>   if (p < (unsigned long) high_memory) {
>     ... use straight copy_[to|from]_user() using p as virtual address ...
>   }
>   ...
>   if (count > 0) {
>     ... use vread/vwrite for accesses past high_memory ...
>   }
> 
> The first condition will inadvertently hold for the VMALLOC region if
> VMALLOC_START < PAGE_OFFSET [which is the case on arm64], but the read
> or write will subsequently fail the virt_addr_valid() check, resulting
> in a -ENXIO return value.
> 
> Given how kmem seems to be living in borrowed time anyway, and given
> the fact that nobody noticed that the read/write interface is broken
> on arm64 in the first place, let's not bother trying to fix it, but
> simply disable the /dev/kmem interface entirely for arm64.
> 
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

FWIW:

Acked-by: Mark Rutland <mark.rutland@arm.com>

Mark.

> ---
> v3: improve commit log
> v2: disable /dev/kmem entirely rather than bandaiding it
> 
>  drivers/char/Kconfig | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
> index 31adbebf812e..8102ee7b3247 100644
> --- a/drivers/char/Kconfig
> +++ b/drivers/char/Kconfig
> @@ -17,6 +17,8 @@ config DEVMEM
>  
>  config DEVKMEM
>  	bool "/dev/kmem virtual device support"
> +	# On arm64, VMALLOC_START < PAGE_OFFSET, which confuses kmem read/write
> +	depends on !ARM64
>  	help
>  	  Say Y here if you want to support the /dev/kmem device. The
>  	  /dev/kmem device is rarely used, but can be used for certain
> -- 
> 2.7.4
>
Ard Biesheuvel June 20, 2017, 11:20 a.m. UTC | #2
On 20 June 2017 at 08:59, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
> As it turns out, arm64 deviates from other architectures in the way it
> maps the VMALLOC region: on most (all?) other architectures, it resides
> strictly above the kernel's direct mapping of DRAM, but on arm64, this
> is the other way around. For instance, for a 48-bit VA configuration,
> we have
>
>   modules : 0xffff000000000000 - 0xffff000008000000   (   128 MB)
>   vmalloc : 0xffff000008000000 - 0xffff7dffbfff0000   (129022 GB)
>   ...
>   vmemmap : 0xffff7e0000000000 - 0xffff800000000000   (  2048 GB maximum)
>             0xffff7e0000000000 - 0xffff7e0003ff0000   (    63 MB actual)
>   memory  : 0xffff800000000000 - 0xffff8000ffc00000   (  4092 MB)
>
> This has mostly gone unnoticed until now, but it does appear that it
> breaks an assumption in the kcore

s/kcore/kmem/

> read/write code, which does something
> like
>
>   if (p < (unsigned long) high_memory) {
>     ... use straight copy_[to|from]_user() using p as virtual address ...
>   }
>   ...
>   if (count > 0) {
>     ... use vread/vwrite for accesses past high_memory ...
>   }
>
> The first condition will inadvertently hold for the VMALLOC region if
> VMALLOC_START < PAGE_OFFSET [which is the case on arm64], but the read
> or write will subsequently fail the virt_addr_valid() check, resulting
> in a -ENXIO return value.
>
> Given how kmem seems to be living in borrowed time anyway, and given
> the fact that nobody noticed that the read/write interface is broken
> on arm64 in the first place, let's not bother trying to fix it, but
> simply disable the /dev/kmem interface entirely for arm64.
>
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
> v3: improve commit log
> v2: disable /dev/kmem entirely rather than bandaiding it
>
>  drivers/char/Kconfig | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
> index 31adbebf812e..8102ee7b3247 100644
> --- a/drivers/char/Kconfig
> +++ b/drivers/char/Kconfig
> @@ -17,6 +17,8 @@ config DEVMEM
>
>  config DEVKMEM
>         bool "/dev/kmem virtual device support"
> +       # On arm64, VMALLOC_START < PAGE_OFFSET, which confuses kmem read/write
> +       depends on !ARM64
>         help
>           Say Y here if you want to support the /dev/kmem device. The
>           /dev/kmem device is rarely used, but can be used for certain
> --
> 2.7.4
>
Greg KH July 17, 2017, 2:18 p.m. UTC | #3
On Tue, Jun 20, 2017 at 01:20:49PM +0200, Ard Biesheuvel wrote:
> On 20 June 2017 at 08:59, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
> > As it turns out, arm64 deviates from other architectures in the way it
> > maps the VMALLOC region: on most (all?) other architectures, it resides
> > strictly above the kernel's direct mapping of DRAM, but on arm64, this
> > is the other way around. For instance, for a 48-bit VA configuration,
> > we have
> >
> >   modules : 0xffff000000000000 - 0xffff000008000000   (   128 MB)
> >   vmalloc : 0xffff000008000000 - 0xffff7dffbfff0000   (129022 GB)
> >   ...
> >   vmemmap : 0xffff7e0000000000 - 0xffff800000000000   (  2048 GB maximum)
> >             0xffff7e0000000000 - 0xffff7e0003ff0000   (    63 MB actual)
> >   memory  : 0xffff800000000000 - 0xffff8000ffc00000   (  4092 MB)
> >
> > This has mostly gone unnoticed until now, but it does appear that it
> > breaks an assumption in the kcore
> 
> s/kcore/kmem/

v4?  :)
Ard Biesheuvel July 17, 2017, 5:04 p.m. UTC | #4
On 17 July 2017 at 15:18, gregkh@linuxfoundation.org
<gregkh@linuxfoundation.org> wrote:
> On Tue, Jun 20, 2017 at 01:20:49PM +0200, Ard Biesheuvel wrote:
>> On 20 June 2017 at 08:59, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
>> > As it turns out, arm64 deviates from other architectures in the way it
>> > maps the VMALLOC region: on most (all?) other architectures, it resides
>> > strictly above the kernel's direct mapping of DRAM, but on arm64, this
>> > is the other way around. For instance, for a 48-bit VA configuration,
>> > we have
>> >
>> >   modules : 0xffff000000000000 - 0xffff000008000000   (   128 MB)
>> >   vmalloc : 0xffff000008000000 - 0xffff7dffbfff0000   (129022 GB)
>> >   ...
>> >   vmemmap : 0xffff7e0000000000 - 0xffff800000000000   (  2048 GB maximum)
>> >             0xffff7e0000000000 - 0xffff7e0003ff0000   (    63 MB actual)
>> >   memory  : 0xffff800000000000 - 0xffff8000ffc00000   (  4092 MB)
>> >
>> > This has mostly gone unnoticed until now, but it does appear that it
>> > breaks an assumption in the kcore
>>
>> s/kcore/kmem/
>
> v4?  :)
>

This is already in mainline as 06c35ef1fdf8d955684448683f7e48ac5f15ccfd
diff mbox

Patch

diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 31adbebf812e..8102ee7b3247 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -17,6 +17,8 @@  config DEVMEM
 
 config DEVKMEM
 	bool "/dev/kmem virtual device support"
+	# On arm64, VMALLOC_START < PAGE_OFFSET, which confuses kmem read/write
+	depends on !ARM64
 	help
 	  Say Y here if you want to support the /dev/kmem device. The
 	  /dev/kmem device is rarely used, but can be used for certain