在set_fs(KERNEL_DS)之后使用内核空间地址调用copy_from_user是否安全?

问题描述 投票:0回答:1

我正在kernel-4.9.168中开发一个linux内核模块,出于某种原因,我想调用另一个模块(vfio)的文件操作。 vfio模块提供了一些文件操作,例如写入,它基本上是这样的:

static ssize_t do_io_rw(struct vfio_pci_device *vdev, bool test_mem,
            void __iomem *io, char __user *buf,
            loff_t off, size_t count, size_t x_start,
            size_t x_end, bool iswrite)
{
    ssize_t done = 0;
    int ret;

    while (count) {
        size_t fillable, filled;

        if (off < x_start)
            fillable = min(count, (size_t)(x_start - off));
        else if (off >= x_end)
            fillable = count;
        else
            fillable = 0;

        if (fillable >= 4 && !(off % 4)) {
            u32 val;

            if (iswrite) {
                if (copy_from_user(&val, buf, 4))
                    return -EFAULT;

                ret = vfio_pci_iowrite32(vdev, test_mem,
                             val, io + off);
                if (ret)
                    return ret;
}

我知道 copy_from_user 会通过将 addr_limit 与 buf 参数进行比较来检查地址是否是用户空间,因此在我自己的模块中,我使用 kernel_write 来绕过用户空间检查,如下所示:

static int my_module_code(struct file *file, struct vhost_virtqueue *vvq)
{
    loff_t pos = yyy;
    unsigned int *idx = &vvq->idx;


    return __kernel_write(file, (char *)idx, 2, &pos);
}

kernel_write 在调用 file->ops->write 之前会 set_fs(KERNEL_DS) ,它工作正常,但我对我的代码感到不舒服,毕竟 copy_from_user 是用 user 命名的。

那么我的代码安全吗?或者有更好的方法来处理这个问题?

linux linux-kernel linux-device-driver
1个回答
0
投票

是的,虽然看起来很奇怪,但应该没问题。

__kernel_write()
之所以做
set_fs(KERNEL_DS)
,正是因为它需要调用需要
__user
地址的函数,同时实际传递kernel地址。确实如此:

old_fs = get_fs();
set_fs(get_ds());
ret = __vfs_write(file, (__force const char __user *)buf, count, pos);
set_fs(old_fs);

其中

__vfs_write
需要
__user
缓冲区,因为它将直接调用
file->f_ops->write()

© www.soinside.com 2019 - 2024. All rights reserved.