且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2021-08-25 21:46:34

非常 有问题.事实上,这是非常危险的.我会在这里给作者一个怀疑的好处,因为他们只是想展示 copy_from_usercopy_to_user 是如何工作的,但他们真的应该提供一个例子太危险了.

It is very questionable. In fact, it's downright dangerous. I'll give the author the benefit of the doubt here since they're just trying to show how copy_from_user and copy_to_user work but they really should have provided an example that wasn't so dangerous.

特别是,因为这本书抒情地讲述了你如何必须格外小心:

Especially since the book waxes lyrical about how you must be extra careful:

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

System calls must carefully verify all their parameters to ensure that they are valid and legal.The system call runs in kernel-space, and if the user can pass invalid input into the kernel without restraint, the system’s security and stability can suffer.

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

and then provides a means for the user to totally annihilate the kernel :-)

我所拥有的副本中的文字说明:

The text from the copy I have states:

让我们考虑一个使用 copy_from_user()copy_to_user() 的系统调用示例.这个系统调用 silly_copy() 完全是一文不值;它将数据从它的第一个参数复制到它的第二个参数中.这是次优的,因为它涉及到内核空间的中间和无关复制而没有任何收益.但它有助于说明这一点.

Let’s consider an example system call that uses both copy_from_user() and copy_to_user().This syscall, silly_copy(), is utterly worthless; it copies data from its first parameter into its second.This is suboptimal in that it involves an intermediate and extraneous copy into kernel-space for no gain. But it helps illustrate the point.

/*
* 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;
}

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


Other than the catastrophic failure of not checking parameters, I'm pretty certain the last parameter of the SYSCALL_DEFINE3 is missing a comma (though that would just be a typo).

一个更好的例子,无需分配任意内存,将是这样的:

A far better example, without having to allocate arbitrary memory, would be along the lines of:

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;
}

建议任何尝试实现该系统调用的人都远离本书中的特定示例,尽管我认为它至少会给您一些良好的内核调试体验:-)


Anyone trying to implement that system call would be well advised to steer away from that particular sample in the book, although I suppose, at a bare minimum, it will give you some good kernel debugging experience :-)