Retme的未来道具研究所

世界線の収束には、逆らえない

一个iovec最大长度是被规定为MAX_RW_COUNT,这个检查由vfs中的rw_copy_check_uvector去做



但是在aio中,命令IOCB_CMD_PWRITE会让buffer被aio_setup_single_vector组装成一个iovec


io_submit -> aio_run_iocb -> aio_setup_single_vector



static ssize_t aio_setup_single_vector(int rw, struct kiocb *kiocb)
{
    if (unlikely(!access_ok(!rw, kiocb->ki_buf, kiocb->ki_nbytes)))
        return -EFAULT;

    kiocb->ki_iovec = &kiocb->ki_inline_vec;
    kiocb->ki_iovec->iov_base = kiocb->ki_buf;
    kiocb->ki_iovec->iov_len = kiocb->ki_nbytes;
    kiocb->ki_nr_segs = 1;
    return 0;
}

kiocb是用户态参数iocb的内核拷贝,所以kiocb->ki_nbytes是用户可控的值,没有校验iov_len是否大于MAX_RW_COUNT(MAX_RW_COUNT=0x7FFFF000)



所以在64位机器上可以设置iov_len为0xffffffff,且绕过access_ok的检查.



static ssize_t do_sock_write(struct msghdr *msg, struct kiocb *iocb,
            struct file *file, const struct iovec *iov,
            unsigned long nr_segs)

static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
                size_t total_len = 0xffffffff)

in pppol2tp_sendmsg
    skb = sock_wmalloc(sk, NET_SKB_PAD + sizeof(struct iphdr) +
               uhlen + session->hdr_len +
               sizeof(ppph) + total_len,
               0, GFP_KERNEL);

struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force,
                 gfp_t priority)
{
    if (force || atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) {
        struct sk_buff *skb = alloc_skb(size, priority);
        if (skb) {
            skb_set_owner_w(skb, sk);
            return skb;
        }
    }
    return NULL;
}

那么在alloc_skb中,把size_t len 转成了int len



skbuff会变得很小,skbuff后面的内存会被写入。


不过对硬件内存要求很高,一般安卓机肯定卡爆


https://code.google.com/p/google-security-research/issues/detail?id=735&can=1&start=500