• Matt Redfearn's avatar
    MIPS: memset.S: Fix return of __clear_user from Lpartial_fixup · 6cd712bf
    Matt Redfearn authored
    commit daf70d89 upstream.
    
    The __clear_user function is defined to return the number of bytes that
    could not be cleared. From the underlying memset / bzero implementation
    this means setting register a2 to that number on return. Currently if a
    page fault is triggered within the memset_partial block, the value
    loaded into a2 on return is meaningless.
    
    The label .Lpartial_fixup\@ is jumped to on page fault. In order to work
    out how many bytes failed to copy, the exception handler should find how
    many bytes left in the partial block (andi a2, STORMASK), add that to
    the partial block end address (a2), and subtract the faulting address to
    get the remainder. Currently it incorrectly subtracts the partial block
    start address (t1), which has additionally been clobbered to generate a
    jump target in memset_partial. Fix this by adding the block end address
    instead.
    
    This issue was found with the following test code:
          int j, k;
          for (j = 0; j < 512; j++) {
            if ((k = clear_user(NULL, j)) != j) {
               pr_err("clear_user (NULL %d) returned %d\n", j, k);
            }
          }
    Which now passes on Creator Ci40 (MIPS32) and Cavium Octeon II (MIPS64).
    Suggested-by: default avatarJames Hogan <jhogan@kernel.org>
    Signed-off-by: default avatarMatt Redfearn <matt.redfearn@mips.com>
    Cc: Ralf Baechle <ralf@linux-mips.org>
    Cc: linux-mips@linux-mips.org
    Cc: stable@vger.kernel.org
    Patchwork: https://patchwork.linux-mips.org/patch/19108/Signed-off-by: default avatarJames Hogan <jhogan@kernel.org>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    6cd712bf
memset.S 6.59 KB