copy_from_user函数的用法

copy_from_user() 是 Linux 内核中用于将数据从用户空间安全复制到内核空间的关键函数。其核心作用是防止用户空间传递非法指针导致内核崩溃,同时处理内存对齐和页错误等问题。

函数原型

1
2
3
#include <linux/uaccess.h> // 必需头文件

unsigned long copy_from_user(void *to, const void __user *from, unsigned long n);

参数说明

参数 类型 说明
to void * 目标地址(内核空间缓冲区)
from const void __user * 源地址(用户空间指针)
n unsigned long 要复制的字节数

返回值

  • 成功:返回 0(所有数据复制完成)
  • 失败:返回未成功复制的字节数(例如部分数据因非法地址失败)

使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 在系统调用中复制用户数据到内核
static long my_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct my_data data_from_user; // 内核空间缓冲区
unsigned long ret;

// 从用户空间复制数据到内核
ret = copy_from_user(&data_from_user, (void __user *)arg, sizeof(struct my_data));

// 检查错误
if (ret != 0) {
pr_err("复制失败,%lu 字节未复制\n", ret);
return -EFAULT; // 返回错误码给用户空间
}

// 安全使用 data_from_user...
return 0;
}

关键注意事项

  1. 安全验证

    • 用户指针 arg 必须用 __user 标记(通过 void __user * 转换)
    • 必须检查返回值!非零值表示部分数据未复制
  2. 上下文限制

    • 可在进程上下文(如系统调用)使用
    • 禁止在中断上下文使用(需改用 copy_from_user_inatomic()
  3. 目标缓冲区

    • to 必须指向已分配的内核内存(栈/堆均可)
    • 需确保缓冲区大小 ≥ n
  4. 典型错误处理

    1
    2
    3
    if (copy_from_user(..., n)) {
    return -EFAULT; // 标准错误码:Bad address
    }

替代函数

函数 用途
copy_to_user() 内核空间 → 用户空间
get_user() / put_user() 复制单个简单类型(int/long 等)
strncpy_from_user() 复制用户空间字符串

工作原理

  1. 检查用户空间地址 from 是否有效(可读)
  2. 处理可能的页错误(Page Fault)
  3. 通过临时映射完成跨空间复制
  4. 返回未能复制的字节数(0 表示完全成功)

提示:在驱动开发中,此函数常用于 ioctl()read()write() 等系统调用实现,是内核与用户空间数据交换的基石。始终优先使用它而非直接解引用用户指针!