Skip to content
  • Andrey Konovalov's avatar
    lib: untag user pointers in strn*_user · 903f433f
    Andrey Konovalov authored
    Patch series "arm64: untag user pointers passed to the kernel", v19.
    
    === Overview
    
    arm64 has a feature called Top Byte Ignore, which allows to embed pointer
    tags into the top byte of each pointer.  Userspace programs (such as
    HWASan, a memory debugging tool [1]) might use this feature and pass
    tagged user pointers to the kernel through syscalls or other interfaces.
    
    Right now the kernel is already able to handle user faults with tagged
    pointers, due to these patches:
    
    1. 81cddd65 ("arm64: traps: fix userspace cache maintenance emulation on a
                 tagged pointer")
    2. 7dcd9dd8 ("arm64: hw_breakpoint: fix watchpoint matching for tagged
    	      pointers")
    3. 276e9327 ("arm64: entry: improve data abort handling of tagged
    	      pointers")
    
    This patchset extends tagged pointer support to syscall arguments.
    
    As per the proposed ABI change [3], tagged pointers are only allowed to be
    passed to syscalls when they point to memory ranges obtained by anonymous
    mmap() or sbrk() (see the patchset [3] for more details).
    
    For non-memory syscalls this is done by untaging user pointers when the
    kernel performs pointer checking to find out whether the pointer comes
    from userspace (most notably in access_ok).  The untagging is done only
    when the pointer is being checked, the tag is preserved as the pointer
    makes its way through the kernel and stays tagged when the kernel
    dereferences the pointer when perfoming user memory accesses.
    
    The mmap and mremap (only new_addr) syscalls do not currently accept
    tagged addresses.  Architectures may interpret the tag as a background
    colour for the corresponding vma.
    
    Other memory syscalls (mprotect, etc.) don't do user memory accesses but
    rather deal with memory ranges, and untagged pointers are better suited to
    describe memory ranges internally.  Thus for memory syscalls we untag
    pointers completely when they enter the kernel.
    
    === Other approaches
    
    One of the alternative approaches to untagging that was considered is to
    completely strip the pointer tag as the pointer enters the kernel with
    some kind of a syscall wrapper, but that won't work with the countless
    number of different ioctl calls.  With this approach we would need a
    custom wrapper for each ioctl variation, which doesn't seem practical.
    
    An alternative approach to untagging pointers in memory syscalls prologues
    is to inspead allow tagged pointers to be passed to find_vma() (and other
    vma related functions) and untag them there.  Unfortunately, a lot of
    find_vma() callers then compare or subtract the returned vma start and end
    fields against the pointer that was being searched.  Thus this approach
    would still require changing all find_vma() callers.
    
    === Testing
    
    The following testing approaches has been taken to find potential issues
    with user pointer untagging:
    
    1. Static testing (with sparse [2] and separately with a custom static
       analyzer based on Clang) to track casts of __user pointers to integer
       types to find places where untagging needs to be done.
    
    2. Static testing with grep to find parts of the kernel that call
       find_vma() (and other similar functions) or directly compare against
       vm_start/vm_end fields of vma.
    
    3. Static testing with grep to find parts of the kernel that compare
       user pointers with TASK_SIZE or other similar consts and macros.
    
    4. Dynamic testing: adding BUG_ON(has_tag(addr)) to find_vma() and running
       a modified syzkaller version that passes tagged pointers to the kernel.
    
    Based on the results of the testing the requried patches have been added
    to the patchset.
    
    === Notes
    
    This patchset is meant to be merged together with "arm64 relaxed ABI" [3].
    
    This patchset is a prerequisite for ARM's memory tagging hardware feature
    support [4].
    
    This patchset has been merged into the Pixel 2 & 3 kernel trees and is
    now being used to enable testing of Pixel phones with HWASan.
    
    Thanks!
    
    [1] http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
    
    [2] https://github.com/lucvoo/sparse-dev/commit/5f960cb10f56ec2017c128ef9d16060e0145f292
    
    [3] https://lkml.org/lkml/2019/6/12/745
    
    [4] https://community.arm.com/processors/b/blog/posts/arm-a-profile-architecture-2018-developments-armv85a
    
    This patch (of 11)
    
    This patch is a part of a series that extends kernel ABI to allow to pass
    tagged user pointers (with the top byte set to something else other than
    0x00) as syscall arguments.
    
    strncpy_from_user and strnlen_user accept user addresses as arguments, and
    do not go through the same path as copy_from_user and others, so here we
    need to handle the case of tagged user addresses separately.
    
    Untag user pointers passed to these functions.
    
    Note, that this patch only temporarily untags the pointers to perform
    validity checks, but then uses them as is to perform user memory accesses.
    
    [andreyknvl@google.com: fix sparc4 build]
     Link: http://lkml.kernel.org/r/CAAeHK+yx4a-P0sDrXTUxMvO2H0CJZUFPffBrg_cU7oJOZyC7ew@mail.gmail.com
    Link: http://lkml.kernel.org/r/c5a78bcad3e94d6cda71fcaa60a423231ae71e4c.1563904656.git.andreyknvl@google.com
    
    
    Signed-off-by: default avatarAndrey Konovalov <andreyknvl@google.com>
    Reviewed-by: default avatarVincenzo Frascino <vincenzo.frascino@arm.com>
    Reviewed-by: default avatarKhalid Aziz <khalid.aziz@oracle.com>
    Acked-by: default avatarKees Cook <keescook@chromium.org>
    Reviewed-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
    Cc: Al Viro <viro@zeniv.linux.org.uk>
    Cc: Dave Hansen <dave.hansen@intel.com>
    Cc: Eric Auger <eric.auger@redhat.com>
    Cc: Felix Kuehling <Felix.Kuehling@amd.com>
    Cc: Jens Wiklander <jens.wiklander@linaro.org>
    Cc: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
    Cc: Mike Rapoport <rppt@linux.ibm.com>
    Cc: Will Deacon <will@kernel.org>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    903f433f