• Christian Brauner's avatar
    ptrace: reintroduce usage of subjective credentials in ptrace_has_cap() · 6b3ad664
    Christian Brauner authored
    Commit 69f594a3 ("ptrace: do not audit capability check when outputing /proc/pid/stat")
    introduced the ability to opt out of audit messages for accesses to various
    proc files since they are not violations of policy.  While doing so it
    somehow switched the check from ns_capable() to
    has_ns_capability{_noaudit}(). That means it switched from checking the
    subjective credentials of the task to using the objective credentials. This
    is wrong since. ptrace_has_cap() is currently only used in
    ptrace_may_access() And is used to check whether the calling task (subject)
    has the CAP_SYS_PTRACE capability in the provided user namespace to operate
    on the target task (object). According to the cred.h comments this would
    mean the subjective credentials of the calling task need to be used.
    This switches ptrace_has_cap() to use security_capable(). Because we only
    call ptrace_has_cap() in ptrace_may_access() and in there we already have a
    stable reference to the calling task's creds under rcu_read_lock() there's
    no need to go through another series of dereferences and rcu locking done
    in ns_capable{_noaudit}().
    
    As one example where this might be particularly problematic, Jann pointed
    out that in combination with the upcoming IORING_OP_OPENAT feature, this
    bug might allow unprivileged users to bypass the capability checks while
    asynchronously opening files like /proc/*/mem, because the capability
    checks for this would be performed against kernel credentials.
    
    To illustrate on the former point about this being exploitable: When
    io_uring creates a new context it records the subjective credentials of the
    caller. Later on, when it starts to do work it creates a kernel thread and
    registers a callback. The callback runs with kernel creds for
    ktask->real_cred and ktask->cred. To prevent this from becoming a
    full-blown 0-day io_uring will call override_cred() and override
    ktask->cred with the subjective credentials of the creator of the io_uring
    instance. With ptrace_has_cap() currently looking at ktask->real_cred this
    override will be ineffective and the caller will be able to open arbitray
    proc files as mentioned above.
    Luckily, this is currently not exploitable but will turn into a 0-day once
    IORING_OP_OPENAT{2} land in v5.6. Fix it now!
    
    Cc: Oleg Nesterov <oleg@redhat.com>
    Cc: Eric Paris <eparis@redhat.com>
    Cc: stable@vger.kernel.org
    Reviewed-by: default avatarKees Cook <keescook@chromium.org>
    Reviewed-by: default avatarSerge Hallyn <serge@hallyn.com>
    Reviewed-by: default avatarJann Horn <jannh@google.com>
    Fixes: 69f594a3 ("ptrace: do not audit capability check when outputing /proc/pid/stat")
    Signed-off-by: default avatarChristian Brauner <christian.brauner@ubuntu.com>
    6b3ad664
ptrace.c 36.5 KB