• Rick Edgecombe's avatar
    x86/shstk: Handle thread shadow stack · b2926a36
    Rick Edgecombe authored
    When a process is duplicated, but the child shares the address space with
    the parent, there is potential for the threads sharing a single stack to
    cause conflicts for each other. In the normal non-CET case this is handled
    in two ways.
    
    With regular CLONE_VM a new stack is provided by userspace such that the
    parent and child have different stacks.
    
    For vfork, the parent is suspended until the child exits. So as long as
    the child doesn't return from the vfork()/CLONE_VFORK calling function and
    sticks to a limited set of operations, the parent and child can share the
    same stack.
    
    For shadow stack, these scenarios present similar sharing problems. For the
    CLONE_VM case, the child and the parent must have separate shadow stacks.
    Instead of changing clone to take a shadow stack, have the kernel just
    allocate one and switch to it.
    
    Use stack_size passed from clone3() syscall for thread shadow stack size. A
    compat-mode thread shadow stack size is further reduced to 1/4. This
    allows more threads to run in a 32-bit address space. The clone() does not
    pass stack_size, which was added to clone3(). In that case, use
    RLIMIT_STACK size and cap to 4 GB.
    
    For shadow stack enabled vfork(), the parent and child can share the same
    shadow stack, like they can share a normal stack. Since the parent is
    suspended until the child terminates, the child will not interfere with
    the parent while executing as long as it doesn't return from the vfork()
    and overwrite up the shadow stack. The child can safely overwrite down
    the shadow stack, as the parent can just overwrite this later. So CET does
    not add any additional limitations for vfork().
    
    Free the shadow stack on thread exit by doing it in mm_release(). Skip
    this when exiting a vfork() child since the stack is shared in the
    parent.
    
    During this operation, the shadow stack pointer of the new thread needs
    to be updated to point to the newly allocated shadow stack. Since the
    ability to do this is confined to the FPU subsystem, change
    fpu_clone() to take the new shadow stack pointer, and update it
    internally inside the FPU subsystem. This part was suggested by Thomas
    Gleixner.
    Co-developed-by: default avatarYu-cheng Yu <yu-cheng.yu@intel.com>
    Suggested-by: default avatarThomas Gleixner <tglx@linutronix.de>
    Signed-off-by: default avatarYu-cheng Yu <yu-cheng.yu@intel.com>
    Signed-off-by: default avatarRick Edgecombe <rick.p.edgecombe@intel.com>
    Signed-off-by: default avatarDave Hansen <dave.hansen@linux.intel.com>
    Reviewed-by: default avatarBorislav Petkov (AMD) <bp@alien8.de>
    Reviewed-by: default avatarKees Cook <keescook@chromium.org>
    Acked-by: default avatarMike Rapoport (IBM) <rppt@kernel.org>
    Tested-by: default avatarPengfei Xu <pengfei.xu@intel.com>
    Tested-by: default avatarJohn Allen <john.allen@amd.com>
    Tested-by: default avatarKees Cook <keescook@chromium.org>
    Link: https://lore.kernel.org/all/20230613001108.3040476-30-rick.p.edgecombe%40intel.com
    b2926a36
shstk.c 4.87 KB