"Linux内核编程"的源代码示例

Mar*_*ark 8 c linux-kernel

正在阅读Robert Love的书,关于系统调用的第5章,并发现这个简单的例子有点可疑:

asmlinkage long sys_silly_copy(unsigned long *src, unsigned long *dst, unsigned long len)
{
   unsigned long buf;

   if (copy_from_user(&buf, src, len))
     return -EFAULT;

   ...
}
Run Code Online (Sandbox Code Playgroud)

我们看到'buf'是'unsigned long'类型的对象并在内核堆栈上定义,即它的初始值可能是垃圾.无论如何,在buf所在的堆栈中复制'len'字节是有效的,即它可以覆盖有用的东西吗?也许这只适用于这个特定的例子?

pax*_*blo 15

这是非常值得怀疑的.事实上,这是非常危险的.我会给作者带来疑问,因为他们只是试图展示如何copy_from_usercopy_to_user工作,但他们真的应该提供一个不那么危险的例子.

特别是因为这本书对你如何必须格外小心抒情:

系统调用必须仔细验证所有参数,以确保它们有效且合法.系统调用在内核空间中运行,如果用户可以无限制地将无效输入传递到内核,系统的安全性和稳定性会受到影响.

然后为用户提供了一种完全消灭内核的方法:-)


我的副本中的文字说明:

让我们考虑同时使用的实例系统调用copy_from_user()copy_to_user().这个系统调用,silly_copy()是一钱不值; 它将数据从其第一个参数复制到第二个参数中.这是次优的,因为它涉及到内核空间的中间和无关副本,无法获得.但它有助于说明这一点.

/*
* silly_copy - pointless syscall that copies the len bytes from
* ‘src’ to ‘dst’ using the kernel as an intermediary in the copy.
* Intended as an example of copying to and from the kernel.
*/
SYSCALL_DEFINE3(silly_copy,
                unsigned long *, src,
                unsigned long *, dst,
                unsigned long len)
{
    unsigned long buf;

    /* copy src, which is in the user’s address space, into buf */
    if (copy_from_user(&buf, src, len))
        return -EFAULT;

    /* copy buf into dst, which is in the user’s address space */
    if (copy_to_user(dst, &buf, len))
        return -EFAULT;

    /* return amount of data copied */
    return len;
}
Run Code Online (Sandbox Code Playgroud)

除了不检查参数的灾难性故障之外,我很确定最后一个参数SYSCALL_DEFINE3是缺少一个逗号(虽然这只是一个错字).

一个更好的例子,不必分配任意内存,将是:

SYSCALL_DEFINE3(silly_copy,
                unsigned long *, src,
                unsigned long *, dst,
                unsigned long,   len)
{
    unsigned long buf[64];                 /* Buffer for chunks */
    unsigned long lenleft = len;           /* Remaining size */
    unsigned long chunklen = sizeof(buf);  /* Initial chunk length */

    /* Loop handling chunk sizes */

    while (lenleft > 0) {
        /* Change chunk length on last chunk */

        if (lenleft < chunklen) chunklen = lenleft;

        /* copy src(user) to buf(kernel) then dst(user) */

        if (copy_from_user(buf, src, chunklen)) return -EFAULT;
        if (copy_to_user(dst, buf, chunklen)) return -EFAULT;

        /* Adjust pointers and remaining size */

        src += chunklen; dst += chunklen; lenleft -= chunklen;
    }

    /* return amount of data copied */
    return len;
}
Run Code Online (Sandbox Code Playgroud)

任何试图实现该系统调用的人都建议远离书中的特定样本,尽管我认为,至少它会给你一些很好的内核调试经验:-)