简体   繁体   English

使用insmod杀死内核模块

[英]kernel module killed on using insmod

I am trying to implement cat command as a kernel module. 我正在尝试将cat命令实现为内核模块。 I know file i/o should not be done in a kernel module,. 我知道文件I / O不应该在内核模块中完成。 Every time I use insmod module.ko I get the output as killed . 每次我使用insmod module.ko ,输出都会被killed How can I fix it? 我该如何解决? Also how can I improve the code? 另外,我该如何改善代码?
kernel version - 4.4 内核版本-4.4
Code: 码:

#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);

Here is a simplified version of the above code which just reads a file. 这是上述代码的简化版本,仅读取文件。 On commenting out the vfs_read part, I'm able to insmod it, but with vfs_read it shows killed. 在注释掉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);

A few things ... 一些东西 ...

You're trying to do all this from the module init callback. 您正在尝试通过模块初始化回调执行所有这些操作。

argc/argv have nothing in them, so that's a problem (ie you could get a segfault). argc/argv中没有任何内容,所以这是一个问题(即,您可能会遇到段错误)。

You could hardwire argc/argv with valid values, but you'd have to recompile and reload the driver with the different files you want to cat. 可以使用有效值对argc/argv进行硬连线,但必须重新编译驱动程序并使用要容纳的其他文件重新加载驱动程序。

But it might be better to accept a module parameter and split it up with a strtok equivalent to populate your argv . 但是,最好接受一个模块参数,并使用等效的strtok将其拆分以填充argv This is the closest thing to an argv equivalent for a driver [which doesn't really exist in exactly the same way as it does for main in an application]. 对于驱动程序,这是最接近argv等效项的东西(它与应用程序中main存在方式并不完全相同)。

You wouldn't have to recompile the module, but, you would still have to reload it each time (giving insmod a different argument each time) 您不必重新编译模块,但是,您仍然每次都必须重新加载它(每次给insmod一个不同的参数)

However, the real/correct way to do this would be, in the module init, to register your driver as a character device using the standard mechanism. 但是,执行此操作的真正/正确方法是,在模块init中,使用标准机制将驱动程序注册为字符设备。 And, likewise, unregister it in the module cleanup routine. 同样,在模块清除例程中注销它。

Then, create a /dev entry (eg /dev/mycat ). 然后,创建一个/dev条目(例如/dev/mycat )。

From an application, open /dev/mycat , and write a list of files you want cat'ed to the file descriptor, one per line. 在应用程序中,打开/dev/mycat ,然后将要接收的文件列表写入文件描述符,每行一个。

Have the driver's write callback routine, parse down the data in the buffer you're passed (ie as if you were implementing your own fgets in userspace), and process the list it gets, performing the cat operation on each file. 使用驱动程序的write回调例程,解析所传递的缓冲区中的数据(即好像您在用户空间中实现自己的fgets ),并处理获取的列表,并对每个文件执行cat操作。

Rather than creating a /dev entry, it might be easier to create a /proc entry (eg /proc/mycat )--YMMV 而不是创建一个/dev项,它可能是更容易地创建一个/proc条目(例如/proc/mycat ) -因人而异

The actual mechanism to communicate the file list to the driver is arbitrary. 将文件列表传达给驱动程序的实际机制是任意的。 You could use an AF_UNIX socket, a named pipe, hook up to a SysV message queue, etc. but the /dev or /proc solution is probably easier. 您可以使用AF_UNIX套接字,命名管道,连接到SysV消息队列等,但是/dev/proc解决方案可能更容易。


UPDATE: 更新:

There seems to be another problem in vfs_read. vfs_read中似乎还有另一个问题。 dmesg gives RIP [] vfs_read+0x5/0x130 and fbcon_switch: detected unhandled fb_set_par error dmesg提供RIP [] vfs_read + 0x5 / 0x130和fbcon_switch:检测到未处理的fb_set_par错误

Amongst other things, you are passing an int as the first arg to vfs_read . 除其他外,您将int作为第一个arg传递给vfs_read The first arg needs to be struct file * [just like vfs_write ]. 第一个arg需要是struct file * [类似于vfs_write ]。

Note: If you're building the driver using the standard mechanism, this would have compiled with -Wall and this would have been flagged at compile time. 注意:如果使用标准机制构建驱动程序,则该驱动程序将使用-Wall进行编译,并且会在编译时进行标记。

Also, you're trying to write [the cat output] to the same file you're reading from, even though you opened it with O_RDONLY (ie equivalent to userspace cat foobar > foobar ). 另外,即使您使用O_RDONLY (即相当于userspace cat foobar > foobar )打开了文件,您仍试图将[cat输出]写入正在读取的文件中。 That's because, for the vfs_write , you did file = fget(f) . 这是因为,对于vfs_write ,您执行了file = fget(f) What you really wanted to do was file = fget(1) 您真正想做的是file = fget(1)

For both vfs_read and vfs_write , you need fget/fput pairings. 对于vfs_readvfs_write ,都需要fget/fput配对。 And, they need to be separate : 并且,它们需要分开

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

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

fput(file_in);
fput(file_out);

You do not want to put buf on the stack. 不想buf在堆栈中。 This produces a race condition. 这产生了竞争条件。 The [kernel] thread could migrate to another processor while I/O is still pending on the vfs_read [AFAIK]. vfs_read [AFAIK]上的I / O仍处于挂起状态时,[kernel]线程可以迁移到另一个处理器。 Other drivers that do similar stuff use kmalloc to get the buffer [and kfree to free it]. 其他执行类似操作的驱动程序也使用kmalloc来获取缓冲区(并使用kfree释放它)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM