【问题标题】:copy_from_user - difficulty in copying double pointer from user spacecopy_from_user - 从用户空间复制双指针的困难
【发布时间】:2012-08-26 05:24:36
【问题描述】:

涉及的结构如下所示。 结构节点{ 诠释一个; 诠释 b; }

struct ioctl_node {
    struct node **ptr;
    int         count; //Stores the no of pointers this ptr is pointing to.
};

在用户空间中,我使用count = 3 填充了一个ioctl_node 结构。 而ptr[0]ptr[2] 指向两个节点类型的结构,而ptr[1]NULL。我希望将其传递给内核。 我已发出 ioctl 调用以将此信息从用户空间传递到内核空间。

我在内核空间做了以下事情。

struct ioctl_node k_node;

copy_from_user(&k_node, arg, sizeof(struct ioctl_node)) //arg is the source

//k_node.count is showing the right value what I have set in the user space.

struct node *tmp = NULL;

然后我做了,copy_from_user(&tmp, k_node.ptr, sizeof(struct node *),这个电话也返回了成功。 但是,我很难在内核空间中正确复制**ptr 的全部内容。 任何人都可以帮忙,我怎么能做到这一点。我应该如何执行下一个 copy_from_user 来复制所有内容。我试过了,但它给出了复制错误。

【问题讨论】:

  • 你不能改变你的规范来复制一个连续的内存区域吗?如果某些内部指针出错,你会怎么做?

标签: c linux linux-kernel


【解决方案1】:

copy_from_user 将一个连续字节块从用户空间复制到内核空间。您需要先复制struct ioctl_node,然后将指针复制到各个节点,然后循环复制struct node。确保分配正确的内存量。由于事先知道节点的数量,因此可以分配它们的数组。

struct node_data {
    size_t node_count;
    struct nodes *nodes;
};
struct node_data *read_nodes(struct ioctl_node_user_pointer *arg)
{
    struct node_data *nd = NULL;
    struct ioctl_node kin = {0};
    struct node *node_user_pointers = NULL;
    int i;
    int err;
    /* Step 1: retrieve the root node */
    nd = kmalloc(sizeof(*nd), GFP_KERNEL);
    if (!nd) {
        err = -ENOMEM;
        goto error;
    }
    if (copy_from_user(ioctl_node_user_pointer, &kin, sizeof(kin))) {
        err = -EFAULT;
        goto error;
    }
    if (kin->count < 0 || kin->count > ((size_t)-1)/sizeof(*nodes)) {
        err = -EINVAL;
        goto error;
    }
    nd->node_count = kin.count;
    /* Step 2: retrieve the pointers to individual nodes */
    node_user_pointers = kmalloc(sizeof(*node_user_pointers) * nd->node_count, GFP_KERNEL);
    if (node_user_pointers) {
        err = -ENOMEM;
        goto error;
    }
    if (copy_from_user(kin->nodes, node_user_pointers, sizeof(*node_user_pointers) * nd->node_count)) {
        err = -EFAULT;
        goto error;
    }
    /* Step 3: retrieve the nodes themselves */
    nd->nodes = kmalloc(sizeof(*nodes) * nd->node_count, GFP_KERNEL);
    if (!nd->nodes) {
        err = -ENOMEM;
        goto error;
    }
    for (i = 0; i < head.count; i++) {
        if (copy_from_user(node_user_pointers[i], nd->nodes + i, sizeof(nd->nodes[0]))) {
            err = -EFAULT;
            goto error;
        }
    }
    kfree(node_user_pointers);
    return nd;
error:
    if (nd) {
        kfree(nd->nodes);
        kfree(nd);
    }
    kfree(node_user_pointers);
    return ERR_PTR(err);
}

【讨论】:

  • 这看起来不够:第一个copy_from_user 是“浅拷贝”,所以kin.ptr 仍然是指向用户空间内存的指针。因此,kin.ptr[i] 无法完成——您必须先分配一个指针数组并复制它们,然后才能开始复制单个节点。或者按照@BasileStarymlevitch 的建议更改 API 以避免双重间接。
  • 我认为您的意思是 if (!node_user_pointers)return -ENOMEM 之前 ;-) linux/err.h 中有一个 ERR_PTR 帮助器以将错误作为指针返回。无条件地kfree(node_user_pointers) 是安全的,因为kfree(NULL) 是无操作的。此外,虽然对于一个简单的示例来说,错误检查有点极端,但最好验证sizeof() * count 不会溢出和换行,否则这会成为用户空间在未分配的内核内存上乱涂乱画的一种简单方法。跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-16
相关资源
最近更新 更多