我要投搞

标签云

收藏小站

爱尚经典语录、名言、句子、散文、日志、唯美图片

当前位置:全民彩票 > 多级反馈 >

Linux内核模块编程--系统调用

归档日期:05-10       文本归类:多级反馈      文章编辑:爱尚语录

  迄今为止,我们做的唯一的事就是用好已定义的内核机制去登记 /proc文件和设备驱动处理程序。如果你想做内核程序员认为你想做的,例如写设备驱动程序,这就对了。但是如果你想做一些不平常的事,在某些地方改变系统的行为呢?那么这大多取决你自己。

  这是内核编程中变得危险的地方。当写下下面的例子,我杀死了 open 系统调用。这意味着我不能打开任何文件,不能运行任何程序,甚至不能 shutdown计算机。我不得不按。幸运的,没有文件消失。为了确保不失去任何文件,在你做insmod 和 rmmod之前请运行 sync 。

  忘记 /proc 文件,忘记设备文件。它们只是次要的细节。 所有进程都要使用的和内核通信的真正的方法是系统调用。当一个进程请求内核的服务时(例如打开文件,分支一个新进程,请求更多内存),这是被使用的机制。如果你想改变内核的行为方式,这是你要做的地方。顺便说一下,如果你想看看一个程序使用了什么系统调用,运行 strace 命令 参数列表。

  通常,一个进程不能访问内核。它不能访问内核的内存和调用内核的函数。CPU硬件强迫这个(那就是为什么叫‘保护模式’的原因)。系统调用是对这个通常的规则的例外。所发生的是进程用适当的值填充寄存器然后调用跳到内核中先前已定义的区域的特定的指令(当然,该区域是用户进程可读但不可写的)。在Intel CPU下,使用中断 0x80 做这个。硬件知道一旦你跳到这个区域,你就不再是运行在严格的用户模式而是操作系统内核--因此你就可以做任何你想做的。

  内核中那个进程可以跳到的区域被称为system_call。 在该区域的程序检查系统调用数,该数告诉内核进程请求什么服务。然后,它在系统调用表(sys_call_table)中查找调用的内核函数的地址。然后它调用该函数并在该函数返回后做一些系统检查,再返回那个进程(或者如果该进程的时间运行完了就返回到一个不同的进程)。如果你想读这个代码,它在源文件arch//kernel/entry.S中的 ENTRY(system_call)行后。

  因此,如果你想改变某个系统调用的工作方法,我们所需要做的是写一个自己的函数以实现它(通常是加一些我们的代码然后再调用原来的函数)并且改变 sys_call_table 中的指针指向我们的函数。因为我们可能随后要移除它而我们不想留下一个不稳定的系统,所以在 cleanup_module 中将那个表恢复成原来的状态是很重要的。

  这儿的源代码是这样一个内核模块的例子。我们想“侦察”某个用户,并在该用户打开一个文件的时候 printk 一个信息。朝着这个目标,我们用我们自己的被称为our_sys_open的函数代替原来的系统调用去打开文件。这个函数检查当前进程的UID(用户的ID)而如果它等于我们要侦察的UID,它就调用 printk显示要打开的文件名。然后,它用相同的参数调用原来的 open 函数做实际的打开文件的工作。

  init_module 代替sys_call_table 中合适的区域并且将原来的指针保存在一个变量中。 cleanup_module 函数使用该变量将没件事恢复成通常的状态。这个方法是危险的,因为两个内核模块同时改变同一个系统调用是可能的。想象我们有两个内核模块A和 B。A 的打开系统调用将是 A_open 而B 的将是 B_open 。现在,当 A 被插入内核,系统调用被 A_open 代替,当它完成时将调用原来的 sys_open 。接着,B 被插入内核,它将用 B_open 代替系统调用,当它完成时将调用它认为的原来的系统调用 A_open。

  现在,如果 B 被先移除,所有的事情将是好的--它将简单的恢复系统调用为将恢复原始的系统调用的 A_open。然而,如果A 被移除然后 B 才被移除,系统将崩溃。A 的移除将恢复系统调用为原始的 sys_open,将 B 排除出那个环。然后,当 B 被移除,它将恢复系统调用为 它 认为是原始的系统调用的不再存在于内存的 A_open。咋看起来我们好象可以通过检查系统调用是否等于我们的函数及是否根本不去改变它(因此 当 B 被移除时不会改变系统调用)来解决这个问题,但那会制造更严重的问题。当 A 被移除,看似系统调用变为 B_open ,因此它不再指向 A_open,因而在它被从内存移除前它不会将它恢复成 sys_open。不幸的, B_open 将仍然试图调用不再存在的 A_open ,因此即使不移除 B 系统也会崩溃。 (译者认为无论是否进行检查,系统都会在A被先移除的情况下在B还未移除时使系统崩溃,因为从作者假设的情况看,B会调用“它”认为的原始的系统调用来完成其功能,在没有检查的情况下,B一样在其存储原系统调用的变量中存储A的函数A_OPEN并进行调用而使系统崩溃。即使B不调用“它”认为的原始的系统调用来完成其功能,系统也会崩溃,因为它无法恢复系统调用。)

本文链接:http://jomsell.com/duojifankui/162.html