Memory management 在内核空间中成功取消引用用户空间指针,而不使用copy_from_user()

Memory management 在内核空间中成功取消引用用户空间指针,而不使用copy_from_user(),memory-management,linux-kernel,linux-device-driver,Memory Management,Linux Kernel,Linux Device Driver,我们公司的代码库中有一个驱动程序有一个bug,已经存在多年了。 基本上,我们通过ioctls调用驱动程序。用户空间和驱动程序空间之间传递的数据存储在结构中,指向数据的指针被送入ioctl。驱动程序负责通过使用copy\u from\u user()解除对指针的引用。但是这段代码已经多年没有这样做了,只是取消了对用户空间指针的引用。到目前为止(据我所知),它还没有引起任何问题 我想知道这个代码怎么这么长时间没有引起任何问题?在什么情况下,直接从用户空间取消对内核空间中指针的引用不会导致问题 在用户

我们公司的代码库中有一个驱动程序有一个bug,已经存在多年了。 基本上,我们通过
ioctl
s调用驱动程序。用户空间和驱动程序空间之间传递的数据存储在
结构中
,指向数据的指针被送入
ioctl
。驱动程序负责通过使用
copy\u from\u user()
解除对指针的引用。但是这段代码已经多年没有这样做了,只是取消了对用户空间指针的引用。到目前为止(据我所知),它还没有引起任何问题

我想知道这个代码怎么这么长时间没有引起任何问题?在什么情况下,直接从用户空间取消对内核空间中指针的引用不会导致问题

在用户空间中

struct InfoToDriver_t data;
data.cmd = DRV_SET_THE_CLOCK;
data.speed = 1000;

ioctl(driverFd, DEVICE_XX_DRIVER_MODIFY, &data);
在驱动程序中

device_xx_driver_ioctl_handler (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
    struct InfoToDriver_t *user_data;

    switch(cmd)
    {
        case DEVICE_XX_DRIVER_MODIFY:
            // what we've been doing for years, BAD
            // But somehow never caused a kernel oops until now
            user_data = (InfoToDriver_t *)arg;
            if (user_data->cmd == DRV_SET_THE_CLOCK)
            { .... }

            // what we're supposed to do
            copy_from_user(user_data, (void *)arg, sizeof(InfoToDriver_t));
            if (user_data->cmd == DRV_SET_THE_CLOCK)
            { ... }

一个可能的答案是,这取决于架构。正如您所看到的,在一个健全的体系结构(如x86或x86-64)上,只需取消对用户指针的引用即可。但是Linux假装支持所有可能的体系结构,有些体系结构不支持简单的去引用。否则,将用户复制到/从用户复制将不存在

将\复制到\用户/从\用户复制\的另一个原因是,usermode端可能与内核端(在另一个线程中)同时修改其内存。在从内核访问usermode内存时,不能假定它的内容被冻结。Rougue用户模式代码可以利用此攻击内核。例如,您可以在执行工作之前探测指向输出数据的指针,但是当您将结果复制回usermode时,该指针已经无效。哎呀。copy_to_用户API确保(应该确保)内核在复制过程中不会崩溃,而会杀死有罪的应用程序

更安全的方法是将整个usermode数据结构复制到内核中(也称为“捕获”),检查此副本的一致性


底线是。。。如果这个驱动程序在特定的体系结构上运行良好,并且没有移植它的计划,那么就没有迫切需要改变它。但是,如果需要捕获usermode数据,或者从usermode复制过程中可能会出现问题,请仔细检查内核代码的健壮性。

我认为,如果修改struct对象,将导致内存崩溃,如果不修改用户数据的内容,将不会导致任何崩溃。用户空间数据所在的页面(arg)例如,可能被调出。在这种情况下,内核将崩溃。@AlexHoppus谢谢。因此,只要用户空间数据(arg)没有被交换出去,直接取消对指针的引用就不会导致内核崩溃?@Splaty这是一个好问题,但我无法想象其他任何事情(但我相信应该会发生)。也许其他人会给你更复杂的例子。