CVE-2016-6187 Exploiting Linux kernel heap off-by-one 利用堆大小差一错误爆破Linux内核(上)

Background(背景)——off-by-one(大小差一)错误介绍

详细了解请移步这里 off-by-one(Off-by-one error),大小差一错误是一类常见的程序设计错误。这方面有一个经典的例子OpenSSH.去Google搜索关键词“OpenSSH off-by-one”可以了解相关状况。具体来说,

  1. if(id < 0 || id > channels_alloc)…

  2. if(id < 0 || id >= channels_alloc)…

第二句应该是正确的写法。举个更通俗的例子:

int a[5],i;

for(i = 1;i < = 5;i++)

a[i]=0;

上述代码定义了长度为5的数组a,循环的目的是给数组元素初始化,赋值为0.但是,循环下标从1开始到5,出现了a[5]=0,这样的不存在的数组元素.这就是典型的“差一错误”(off-by-one).

Introduction(前言)

我认为我决定介绍该漏洞的理由是因为当我把它发在推特上时,我收到了一些私信说这个内核路径不存在漏洞(找不到漏洞在哪)或者该漏洞不能利用。另一个的理由就是我想在实际漏洞利用中尝试userfaultfd() 系统调用,我需要一个真实的UAF漏洞来进行实验。

首先,我不知道这个漏洞影响到哪些Linux发行版本的内核。我检查了ubuntu的最新发行版本Yakkety,发现其没有受该漏洞影响。漏洞在Linux kernel source tree被引入,在Linux kernel source tree中被修复。

因为我需要一个含有该漏洞的ubuntu内核,我在ubuntu16.04(x86_64)上编译了4.5.1内核。另外该漏洞仅仅影响像ubuntu一样默认使用AppArmor作为LSM(Linux安全模块)的发行版本,像centos使用SELinux就不受该漏洞的影响。

Vulnerability(漏洞介绍)

当写入/proc/self/attr/current 会使用内核中的proc_pid_attr_write() 函数。接下来介绍的代码是漏洞被引入之前的:

static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
{
struct inode * inode = file_inode(file);
char *page;
ssize_t length;
struct task_struct *task = get_proc_task(inode);

    length = -ESRCH;
    if (!task)
            goto out_no_task;
    if (count > PAGE_SIZE)                            [1]
            count = PAGE_SIZE;

    /* No partial writes. */
    length = -EINVAL;
    if (*ppos != 0)
            goto out;

    length = -ENOMEM;
    page = (char*)__get_free_page(GFP_TEMPORARY);     [2]
    if (!page)
            goto out;

    length = -EFAULT;
    if (copy_from_user(page, buf, count))             [3]
            goto out_free;

    /* Guard against adverse ptrace interaction */
    length = mutex_lock_interruptible(&task-;>signal->cred_guard_mutex);
    if (length < 0)
            goto out_free;

    length = security_setprocattr(task,
                                  (char*)file->f_path.dentry->d_name.name,
                                  (void*)page, count);

查看完整版请移步看雪论坛

[翻译]CVE-2016-6187 Exploiting Linux kernel heap off-by-one 利用堆大小差一错误爆破Linux内核(上)