【发布时间】:2017-06-17 19:09:20
【问题描述】:
我正在尝试将 cat 命令实现为内核模块。我知道文件 i/o 不应该在内核模块中完成。每次我使用 insmod module.ko 时,我都会得到输出为 killed 。我该如何解决?另外我该如何改进代码?
内核版本 - 4.4
代码:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/unistd.h>
#include <linux/syscalls.h>
#include <linux/fcntl.h>
#include <asm/uaccess.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/file.h>
static char* argv[10];
static int argc = 1;
module_param_array(argv, int, &argc , 0);
static void cat(int f, char *s)
{
char buf[8192];
struct file *file;
loff_t pos = 0;
long n;
mm_segment_t old_fs = get_fs();
set_fs(KERNEL_DS);
while((n = vfs_read(f, buf, (long)sizeof buf, &pos)) > 0)
{
//write(1, buf, n);
file = fget(f);
if (file) {
vfs_write(file, buf, (long)sizeof buf, &pos);
fput(file);
}
}
set_fs(old_fs);
}
static void __init hello_init(void)
{
int f, i;
if(argc == 1)
cat(0, "<stdin>");
else for(i=1; i<argc; i++)
{
f = filp_open(argv[i], O_RDONLY, 0);
if(f < 0)
printk("error");
else{
cat(f, argv[i]);
filp_close(f);
}
}
}
static void __exit hello_cleanup(void)
{
printk(KERN_INFO "Cleaning up module.\n");
}
module_init(hello_init);
module_exit(hello_cleanup);
这是上述代码的简化版本,它只是读取一个文件。在注释掉 vfs_read 部分时,我可以对其进行安装,但使用 vfs_read 它显示已被杀死。
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/syscalls.h>
#include <linux/fcntl.h>
#include <asm/uaccess.h>
static void read_file(char *filename)
{
int fd;
char buf[1];
loff_t f_pos = 0;
mm_segment_t old_fs = get_fs();
set_fs(KERNEL_DS);
fd = filp_open(filename, O_RDONLY, 0);
if (fd >= 0) {
printk(KERN_DEBUG);
while (vfs_read(fd, buf, 1, &f_pos) == 1) //if this
printk("%c", buf[0]); //and this is removed I'm able to insmod it
printk("\n");
sys_close(fd);
}
set_fs(old_fs);
}
static int __init init(void)
{
read_file("/etc/shadow");
return 0;
}
static void __exit exit(void)
{ }
module_init(init);
module_exit(exit);
【问题讨论】:
-
您是否尝试过调试您的代码,以确定哪一行代码崩溃?对于调试内核代码,您可以在某些点之后添加
printk()调用。此外,如果代码崩溃,dmesg可能会提供更多相关信息。 -
dmesg 给出 RIP [
] vfs_read+0x5/0x130 和 fbcon_switch:检测到未处理的 fb_set_par 错误 -
你的
hello_init函数中的哪个分支被执行了? (是cat(0),还是cat(f))?请注意,您的模块接受 指针数组,这可能不是您所期望的。也就是说,argv[i]是一个指向 .. 垃圾的指针,取消引用它(例如在filp_open()调用中)是一个明确错误。 -
嗯,简化版很清楚。第一件事:
filp_open()返回struct file*(不是int),检查成功应该是!IS_ERR(f)。如果filp_open成功,您可以将它返回的值传递给vfs_read()。使用fput(f)执行关闭文件。 -
@Tsyvarev 非常感谢,它成功了
标签: c linux file io linux-kernel