Skip to content
  • Will Deacon's avatar
    word-at-a-time: avoid undefined behaviour in zero_bytemask macro · ec6931b2
    Will Deacon authored
    
    
    The asm-generic, big-endian version of zero_bytemask creates a mask of
    bytes preceding the first zero-byte by left shifting ~0ul based on the
    position of the first zero byte.
    
    Unfortunately, if the first (top) byte is zero, the output of
    prep_zero_mask has only the top bit set, resulting in undefined C
    behaviour as we shift left by an amount equal to the width of the type.
    As it happens, GCC doesn't manage to spot this through the call to fls(),
    but the issue remains if architectures choose to implement their shift
    instructions differently.
    
    An example would be arch/arm/ (AArch32), where LSL Rd, Rn, #32 results
    in Rd == 0x0, whilst on arch/arm64 (AArch64) LSL Xd, Xn, #64 results in
    Xd == Xn.
    
    Rather than check explicitly for the problematic shift, this patch adds
    an extra shift by 1, replacing fls with __fls. Since zero_bytemask is
    never called with a zero argument (has_zero() is used to check the data
    first), we don't need to worry about calling __fls(0), which is
    undefined.
    
    Cc: <stable@vger.kernel.org>
    Cc: Victor Kamensky <victor.kamensky@linaro.org>
    Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    ec6931b2