1.7什么是内核守护进程
最后我们几乎已经要结束我们的基础部分了,现在我会解释一下内核守护进程(/sbin/kerneld)的工作原理。正如名字所暗示的那样,这是一个在用户空间等待任务的进程。首先,为了能够使用kerneld的功能,你必须在编译内核的时候加上kerneld选项.kerneld的工作方式如下:如果内核想获取一个资源(当然是在内核空间中的),而这个资源当前并不能满足需求,内核是不会引发一个错误的.他会向kerneld请求这种资源.如果kerneld能够提供这种资源,他就会载入所需要的LKM,内核就能继续工作了.通过这种机制,使得LKMs可以在当他被需要/不需要时被加载/卸载.必须清楚这项工作必须在内核空间和用户空间同时进行.
kerneld存在于用户空间.当内核需要一个新的模块时,这个守护进程会接收到内核传给他的一个字符串来知道到底该加载那个内核.有可能内核送过来的是一个真实的设备名(而不是文件名),像eth0.在这种情况下系统就要查找/etc/modules.conf里面的别名来确定到底加载那个LKM到系统中.
下面的行表明了eth0用的是一个DEC Tulip driver LKM:
# /etc/modules.conf # 或者 /etc/conf.modules - 这是不一样的
alias eth0 tulip
这是kerneld守护进程在用户空间这边的工作情况.在内核那边主要由4个函数来表示.这些函数都是基于kerneld_send调用的.kerneld_send调用的确切形式可以看linux/kerneld.h.下面的表列出了上面提到的4个函数.
函数描述
int sprintf (char *buf, const char *fmt, ...);
int vsprintf (char *buf, const char *fmt, va_list args);
用来将数据格式化为字符串的函数
int request_module (const char *name);
告诉kerneld内核需要某个模块(给出名字或者真实的ID/设备名)
int release_module (const char* name, int waitflag);
卸载一个模块
int delayed_release_module (const char *name);
推迟卸载
int cancel_release_module (const char *name);
取消一个推迟卸载调用
注意:Kernel 2.2使用另外一种机制来请求模块.可以看第5部分.
1.8 创建你自己的设备
附录A介绍了一个TTY攻击工具.他使用一个设备来纪录结果.因此我们必须来看一个非常简单的关于设备驱动程序的例子.来看看下面的代码(这是一个非常基本的驱动,写他的目的仅仅是为了论述,他几乎没有任何操作......)
#define MODULE
#define __KERNEL__
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <asm/fcntl.h>
#include <asm/errno.h>
#include <linux/types.h>
#include <linux/dirent.h>
#include <sys/mman.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <linux/malloc.h>
static int driver_open(struct inode *i, struct file *f)
{
printk("<1>Open Function\n");
return 0;
}
/*注册我们提供给设备的每一个函数*/
static struct file_operations fops = {
NULL, /*lseek*/
NULL, /*read*/
NULL, /*write*/
NULL, /*readdir*/
NULL, /*select*/
NULL, /*ioctl*/
NULL, /*mmap*/
driver_open, /*open, take a look at my dummy open function*/
NULL, /*release*/
NULL /*fsync...*/
};
int init_module(void)
{
/*用ID 40和名字 driver给驱动注册*/
if(register_chrdev(40, "driver", &fops)) return -EIO;
return 0;
}
void cleanup_module(void)
{
/*取消注册*/
unregister_chrdev(40, "driver");
}
最为重要的函数是register_chrdev(....).这个函数用ID 40给我们的驱动注册.如果你想使用这个驱动.照如下步骤做:
# mknode /dev/driver c 40 0
# insmod driver.o
这样你就能够存取这个设备了(但是由于缺乏时间,我并没有在其中实现任何功能....).file_operations结构显示了我们这个驱动可以提供给系统的所有函数(操作).正如你所看到的,我仅仅实现了一个十分(!)基本的笨蛋函数.这个函数仅仅打印一些东西.要清楚的是通过上面提到的方法你可以很容易的实现你自己的设备.可以做一些试验.如果你想纪录一些数据(比如说击键),你可以在你的驱动中间建立一个缓冲区.
摘自《赛迪网》 pragmatic/THC,(版本1.0)/文