gpt4 book ai didi

c - 内核模块在使用 insmod 时被杀死

转载 作者:太空宇宙 更新时间:2023-11-04 10:25:05 27 4
gpt4 key购买 nike

我正在尝试将 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 部分时,我能够对其进行 insmod,但是对于 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);

最佳答案

一些事情......

您正在尝试从模块初始化回调中执行所有这些操作。

argc/argv 中没有任何内容,所以这是一个问题(即您可能会遇到段错误)。

可以使用有效值硬连线argc/argv,但您必须重新编译并使用您想要 cat 的不同文件重新加载驱动程序。

但是接受一个模块参数并用一个 strtok 等价于填充你的 argv 来拆分它可能会更好。这是与驱动程序的 argv 等价物最接近的东西 [它的存在方式与应用程序中的 main 完全不同]。

您不必重新编译该模块,但是,您仍然每次都必须重新加载它(每次给 insmod 一个不同的参数)

但是,真正/正确的方法是在模块初始化中使用标准机制将您的驱动程序注册为字符设备。同样,在模块清理例程中注销它。

然后,创建一个 /dev 条目(例如 /dev/mycat)。

从一个应用程序中,打开 /dev/mycat,然后将您想要 cat 的文件列表写入文件描述符,每行一个。

让驱动程序的 write 回调例程,解析您传递的缓冲区中的数据(即,就像您在用户空间中实现自己的 fgets 一样),以及处理它获得的列表,对每个文件执行 cat 操作。

与其创建 /dev 条目,不如创建 /proc 条目(例如 /proc/mycat)--YMMV

将文件列表传送给驱动程序的实际机制是任意的。您可以使用 AF_UNIX 套接字、命名管道、连接到 SysV 消息队列等,但 /dev/proc 解决方案可能更容易。


更新:

There seems to be another problem in vfs_read. dmesg gives RIP [] vfs_read+0x5/0x130 and fbcon_switch: detected unhandled fb_set_par error

除其他事项外,您将 int 作为第一个 arg 传递给 vfs_read。第一个 arg 需要是 struct file * [就像 vfs_write]。

注意:如果您使用标准机制构建驱动程序,这将使用 -Wall 进行编译,并且会在编译时进行标记。

此外,您正在尝试将 [cat 输出] 写入您正在读取的同一个文件,即使您使用 O_RDONLY 打开它(即相当于用户空间 cat foobar > foobar).那是因为,对于 vfs_write,您执行了 file = fget(f)。你真正想做的是 file = fget(1)

对于 vfs_readvfs_write,您需要 fget/fput 配对。而且,它们需要分开:

file_in = fget(f);
file_out = fget(1);

// read/write loop ...
while (1) {
...
}

fput(file_in);
fput(file_out);

想要将 buf 放入堆栈。这会产生竞争条件。 [内核] 线程可以迁移到另一个处理器,而 I/O 仍在 vfs_read [AFAIK] 上挂起。其他执行类似操作的驱动程序使用 kmalloc 获取缓冲区 [并使用 kfree 释放它]。

关于c - 内核模块在使用 insmod 时被杀死,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41972971/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com