编译内核自定义系统调用遇struct pt_regs及raw_copy_to_user错误求助
问题解决:内核编译及自定义系统调用错误
1. 编译错误:raw_copy_to_user 类型冲突
错误原因
你手动添加的 typedef unsigned int __bitwise gfp_t; 与内核头文件中已有的 gfp_t 定义重复,导致依赖该类型的函数(如 raw_copy_to_user)类型解析混乱,触发冲突。
解决方法
直接删除代码中的这一行:
typedef unsigned int __bitwise gfp_t;
内核头文件会自动包含 gfp_t 的定义,无需手动重复声明。
2. IntelliSense错误:struct pt_regs 类型不完整
错误原因
VS Code的IntelliSense未找到内核中 struct pt_regs 的定义,因为你的 c_cpp_properties.json 仅包含了系统默认头文件路径,而内核架构相关头文件(如 pt_regs 的定义)位于内核源码目录内,不在 /usr/include 下。
解决方法
修改 c_cpp_properties.json 的 includePath,添加你的内核源码绝对路径(示例中使用 ~/linux-5.15,请替换为实际路径):
{ "configurations": [ { "name": "Linux", "includePath": [ "${workspaceFolder}/**", "/usr/**", "~/linux-5.15/**", "~/linux-5.15/arch/x86/include/**" ], "defines": [], "compilerPath": "/usr/bin/gcc", "cStandard": "gnu17", "cppStandard": "gnu++17", "intelliSenseMode": "linux-gcc-x64", "configurationProvider": "ms-vscode.cpptools" } ], "version": 4 }
同时在自定义系统调用代码中添加头文件:
#include <asm/ptrace.h>
该头文件包含 struct pt_regs 的定义,可解决IntelliSense的类型识别问题。
3. 自定义系统调用代码的其他潜在问题
除上述错误外,代码还有几处逻辑问题需修正,否则编译通过后也会运行出错:
- 禁止直接对用户空间指针调用
strlen:src是用户空间指针,直接在内核中调用strlen会触发非法内存访问,需先安全计算用户空间字符串长度。 - 冗余的手动拷贝逻辑:内核空间内拷贝字符串可直接使用
strcpy,无需手动循环。 - 缺少内存分配失败检查:
kmalloc可能返回NULL,需添加空指针检查避免崩溃。
修正后的代码示例:
// strcpy.c: code for the new system call #include <linux/kernel.h> #include <linux/slab.h> // kmalloc() #include <asm/uaccess.h> // copy_from_user(), copy_to_user() #include <linux/syscalls.h>// SYSCALL_DEFINE2 #include <linux/types.h> // 确保内核类型定义被包含 #include <asm/ptrace.h> // struct pt_regs定义 #include <linux/string.h> // strcpy() SYSCALL_DEFINE2(strcpy, char __user*, dest, const char __user*, src) { int size = 0; char *tmp1, *tmp2; char ch; // 安全计算用户空间字符串长度 while (copy_from_user(&ch, src + size, 1) == 0 && ch != '\0') { size++; } size++; // 加上终止符'\0'的长度 // 分配内核内存并检查是否成功 tmp1 = kmalloc(size, GFP_KERNEL); tmp2 = kmalloc(size, GFP_KERNEL); if (!tmp1 || !tmp2) { printk(KERN_ALERT "kmalloc failed\n"); kfree(tmp1); kfree(tmp2); return -ENOMEM; } // 从用户空间拷贝字符串到内核 if (copy_from_user(tmp1, src, size) != 0) { printk(KERN_ALERT "copy_from_user error\n"); kfree(tmp1); kfree(tmp2); return -EFAULT; } // 内核空间内拷贝字符串 strcpy(tmp2, tmp1); // 拷贝到用户空间 if (copy_to_user(dest, tmp2, size) != 0) { printk(KERN_ALERT "copy_to_user error\n"); kfree(tmp1); kfree(tmp2); return -EFAULT; } kfree(tmp1); kfree(tmp2); printk(KERN_ALERT "done system call strcpy...\n"); return size; // 返回拷贝的字节数更符合系统调用规范 }
内容的提问来源于stack exchange,提问作者Mals
相关产品推荐
相关产品推荐

