PZ issue 735
作者:retme 发布时间:February 26, 2016 分类:AndroidSec No Comments
一个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