21 Jan, 2016

1 commit

  • By checking the effective credentials instead of the real UID / permitted
    capabilities, ensure that the calling process actually intended to use its
    credentials.

    To ensure that all ptrace checks use the correct caller credentials (e.g.
    in case out-of-tree code or newly added code omits the PTRACE_MODE_*CREDS
    flag), use two new flags and require one of them to be set.

    The problem was that when a privileged task had temporarily dropped its
    privileges, e.g. by calling setreuid(0, user_uid), with the intent to
    perform following syscalls with the credentials of a user, it still passed
    ptrace access checks that the user would not be able to pass.

    While an attacker should not be able to convince the privileged task to
    perform a ptrace() syscall, this is a problem because the ptrace access
    check is reused for things in procfs.

    In particular, the following somewhat interesting procfs entries only rely
    on ptrace access checks:

    /proc/$pid/stat - uses the check for determining whether pointers
    should be visible, useful for bypassing ASLR
    /proc/$pid/maps - also useful for bypassing ASLR
    /proc/$pid/cwd - useful for gaining access to restricted
    directories that contain files with lax permissions, e.g. in
    this scenario:
    lrwxrwxrwx root root /proc/13020/cwd -> /root/foobar
    drwx------ root root /root
    drwxr-xr-x root root /root/foobar
    -rw-r--r-- root root /root/foobar/secret

    Therefore, on a system where a root-owned mode 6755 binary changes its
    effective credentials as described and then dumps a user-specified file,
    this could be used by an attacker to reveal the memory layout of root's
    processes or reveal the contents of files he is not allowed to access
    (through /proc/$pid/cwd).

    [akpm@linux-foundation.org: fix warning]
    Signed-off-by: Jann Horn
    Acked-by: Kees Cook
    Cc: Casey Schaufler
    Cc: Oleg Nesterov
    Cc: Ingo Molnar
    Cc: James Morris
    Cc: "Serge E. Hallyn"
    Cc: Andy Shevchenko
    Cc: Andy Lutomirski
    Cc: Al Viro
    Cc: "Eric W. Biederman"
    Cc: Willy Tarreau
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Jann Horn
     

11 Sep, 2014

1 commit

  • The C operator < 0, b-c < 0, but a-c >
    0.

    Note that it makes absolutely no difference that a transmogrying bijection
    has been applied before the comparison is done. In fact, had the
    obfuscation not been done, one could probably not observe the bug
    (assuming all values being compared always lie in one half of the address
    space, the mathematical value of a-b is always representable in a long).
    As it stands, one can easily obtain three file descriptors exhibiting the
    non-transitivity of kcmp().

    Side note 1: I can't see that ensuring the MSB of the multiplier is
    set serves any purpose other than obfuscating the obfuscating code.

    Side note 2:
    #include
    #include
    #include
    #include
    #include
    #include
    #include

    enum kcmp_type {
    KCMP_FILE,
    KCMP_VM,
    KCMP_FILES,
    KCMP_FS,
    KCMP_SIGHAND,
    KCMP_IO,
    KCMP_SYSVSEM,
    KCMP_TYPES,
    };
    pid_t pid;

    int kcmp(pid_t pid1, pid_t pid2, int type,
    unsigned long idx1, unsigned long idx2)
    {
    return syscall(SYS_kcmp, pid1, pid2, type, idx1, idx2);
    }
    int cmp_fd(int fd1, int fd2)
    {
    int c = kcmp(pid, pid, KCMP_FILE, fd1, fd2);
    if (c < 0) {
    perror("kcmp");
    exit(1);
    }
    assert(0 < 3);
    return c;
    }
    int cmp_fdp(const void *a, const void *b)
    {
    static const int normalize[] = {0, -1, 1};
    return normalize[cmp_fd(*(int*)a, *(int*)b)];
    }
    #define MAX 100 /* This is plenty; I've seen it trigger for MAX==3 */
    int main(int argc, char *argv[])
    {
    int r, s, count = 0;
    int REL[3] = {0,0,0};
    int fd[MAX];
    pid = getpid();
    while (count < MAX) {
    r = open("/dev/null", O_RDONLY);
    if (r < 0)
    break;
    fd[count++] = r;
    }
    printf("opened %d file descriptors\n", count);
    for (r = 0; r < count; ++r) {
    for (s = r+1; s < count; ++s) {
    REL[cmp_fd(fd[r], fd[s])]++;
    }
    }
    printf("== %d\t< %d\t> %d\n", REL[0], REL[1], REL[2]);
    qsort(fd, count, sizeof(fd[0]), cmp_fdp);
    memset(REL, 0, sizeof(REL));

    for (r = 0; r < count; ++r) {
    for (s = r+1; s < count; ++s) {
    REL[cmp_fd(fd[r], fd[s])]++;
    }
    }
    printf("== %d\t< %d\t> %d\n", REL[0], REL[1], REL[2]);
    return (REL[0] + REL[2] != 0);
    }

    Signed-off-by: Rasmus Villemoes
    Reviewed-by: Cyrill Gorcunov
    "Eric W. Biederman"
    Cc:
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Rasmus Villemoes
     

21 Dec, 2012

1 commit

  • This makes it compile on s390. After all the ptrace_may_access
    (which we use this file) is declared exactly in linux/ptrace.h.

    This is preparatory work to wire this syscall up on all archs.

    Signed-off-by: Cyrill Gorcunov
    Signed-off-by: Alexander Kartashov
    Cc: Heiko Carstens
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Cyrill Gorcunov
     

01 Jun, 2012

1 commit

  • While doing the checkpoint-restore in the user space one need to determine
    whether various kernel objects (like mm_struct-s of file_struct-s) are
    shared between tasks and restore this state.

    The 2nd step can be solved by using appropriate CLONE_ flags and the
    unshare syscall, while there's currently no ways for solving the 1st one.

    One of the ways for checking whether two tasks share e.g. mm_struct is to
    provide some mm_struct ID of a task to its proc file, but showing such
    info considered to be not that good for security reasons.

    Thus after some debates we end up in conclusion that using that named
    'comparison' syscall might be the best candidate. So here is it --
    __NR_kcmp.

    It takes up to 5 arguments - the pids of the two tasks (which
    characteristics should be compared), the comparison type and (in case of
    comparison of files) two file descriptors.

    Lookups for pids are done in the caller's PID namespace only.

    At moment only x86 is supported and tested.

    [akpm@linux-foundation.org: fix up selftests, warnings]
    [akpm@linux-foundation.org: include errno.h]
    [akpm@linux-foundation.org: tweak comment text]
    Signed-off-by: Cyrill Gorcunov
    Acked-by: "Eric W. Biederman"
    Cc: Pavel Emelyanov
    Cc: Andrey Vagin
    Cc: KOSAKI Motohiro
    Cc: Ingo Molnar
    Cc: H. Peter Anvin
    Cc: Thomas Gleixner
    Cc: Glauber Costa
    Cc: Andi Kleen
    Cc: Tejun Heo
    Cc: Matt Helsley
    Cc: Pekka Enberg
    Cc: Eric Dumazet
    Cc: Vasiliy Kulikov
    Cc: Alexey Dobriyan
    Cc: Valdis.Kletnieks@vt.edu
    Cc: Michal Marek
    Cc: Frederic Weisbecker
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Cyrill Gorcunov