]> git.baikalelectronics.ru Git - kernel.git/commit
ARM: uaccess: fix DACR mismatch with nested exceptions
authorRussell King <rmk+kernel@armlinux.org.uk>
Sun, 3 May 2020 12:24:07 +0000 (13:24 +0100)
committerRussell King <rmk+kernel@armlinux.org.uk>
Sun, 3 May 2020 16:30:27 +0000 (17:30 +0100)
commit38469f4d296d9328b9057fef8ff07cbf1b17feb3
tree86f5eee6c2f3d5cbd5573b578fe512567dddaa28
parent9b775099cca3cd030bfd9e367200fac42ca21bba
ARM: uaccess: fix DACR mismatch with nested exceptions

Tomas Paukrt reports that his SAM9X60 based system (ARM926, ARMv5TJ)
fails to fix up alignment faults, eventually resulting in a kernel
oops.

The problem occurs when using CONFIG_CPU_USE_DOMAINS with commit
ddbf4436793e ("ARM: save and reset the address limit when entering an
exception").  This is because the address limit is set back to
TASK_SIZE on exception entry, and, although it is restored on exception
exit, the domain register is not.

Hence, this sequence can occur:

  interrupt
    pt_regs->addr_limit = addr_limit // USER_DS
    addr_limit = USER_DS
    alignment exception
    __probe_kernel_read()
      old_fs = get_fs() // USER_DS
      set_fs(KERNEL_DS)
        addr_limit = KERNEL_DS
        dacr.kernel = DOMAIN_MANAGER
        interrupt
          pt_regs->addr_limit = addr_limit // KERNEL_DS
          addr_limit = USER_DS
          alignment exception
          __probe_kernel_read()
            old_fs = get_fs() // USER_DS
            set_fs(KERNEL_DS)
              addr_limit = KERNEL_DS
              dacr.kernel = DOMAIN_MANAGER
            ...
            set_fs(old_fs)
              addr_limit = USER_DS
              dacr.kernel = DOMAIN_CLIENT
          ...
          addr_limit = pt_regs->addr_limit // KERNEL_DS
        interrupt returns

At this point, addr_limit is correctly restored to KERNEL_DS for
__probe_kernel_read() to continue execution, but dacr.kernel is not,
it has been reset by the set_fs(old_fs) to DOMAIN_CLIENT.

This would not have happened prior to the mentioned commit, because
addr_limit would remain KERNEL_DS, so get_fs() would have returned
KERNEL_DS, and so would correctly nest.

This commit fixes the problem by also saving the DACR on exception
entry if either CONFIG_CPU_SW_DOMAIN_PAN or CONFIG_CPU_USE_DOMAINS are
enabled, and resetting the DACR appropriately on exception entry to
match addr_limit and PAN settings.

Fixes: ddbf4436793e ("ARM: save and reset the address limit when entering an exception")
Reported-by: Tomas Paukrt <tomas.paukrt@advantech.cz>
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
arch/arm/include/asm/uaccess-asm.h