Skip to content
  • Russell King's avatar
    ARM: uaccess: fix DACR mismatch with nested exceptions · 71f8af11
    Russell King authored
    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
    e6978e4b ("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: e6978e4b
    
     ("ARM: save and reset the address limit when entering an exception")
    Reported-by: default avatarTomas Paukrt <tomas.paukrt@advantech.cz>
    Signed-off-by: default avatarRussell King <rmk+kernel@armlinux.org.uk>
    71f8af11