万卷书   首页 > 电脑书籍 > Linux >Linux内核模块编程--系统调用
 
 我可以想到两个预防的办法。第一个是恢复调用为原始值 sys_open。不幸的, sys_open 不是内核系统表 /proc/ksyms 中的一部分,因此不能访问它。另一个就是使用引用计数来防止一旦模块被加载就可以随便被 rmmod。这对产品模块是一个好办法,但不适合做教育性的范例--这也是我为什么不在这做的原因。

ex syscall.c

/* syscall.c
*
* 系统调用“偷窃”范例
*/

/* Copyright (C) 1998-99 by Ori Pomerantz */

/* 必要头文件 */

/* 标准头文件 */
#include /* 内核工作 */
#include /* 明确指定是模块 */

/* 处理 CONFIG_MODVERSIONS */
#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include
#endif

#include /* 系统调用列表 */

/* 为了当前进程结构,我们需要这个知道当前用户是谁 */
#include

/* 在 2.2.3 版/usr/include/linux/version.h 包含该宏但 2.0.35 不包含
* 加入以备需要 */
#ifndef KERNEL_VERSION
#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))
#endif

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
#include
#endif

/* 系统调用表(函数表)。我们只将定义为外部的即可,当我们insmod的时候内核会为我们填充它 */
extern void *sys_call_table[];

/* 我们想侦察的UID - 将从命令行填充 */
int uid;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
MODULE_PARM(uid, "i");
#endif

/* 原始的系统调用的指针。我们保存它而不是调用原始函数是因为其他某人可能在我们之前可能已经代替了
* 原始的系统调用(sys_open)。注意这并不是100%安全的,因为如果另一个模块在我们之前代替了
* sys_open,然后当我们被插入内核,我们将调用那个模块里的函数-它可能在我们之前又被移除了。
*
* 另一个原因是我们不能得到 sys_open。 它是静态变量,因此是不可导出的。 */
asmlinkage int (*original_call)(const char *, int, int);

/* 因为某些原因,在 2.2.3 版中current->uid 为0而非真正的用户 ID。我试图找出什么地方错了,但
* 不能在短时间内完成,而且我很懒-因此我仅仅使用系统调用得到UID,这是进程使用的方法。
*
* 因为某些原因,在我重新编译内核后这个问题没有了。
*/
asmlinkage int (*getuid_call)();

/* 我们将用来代替 sys_open 的函数 (当你调用 open 系统调用时这个函数被调用)。为了得到精确的原型
* 连同参数的数目和类型,我们首先找到了原始的函数(在 fs/open.c 中)。
*
* 理论上,这意味着我们将局限于内核的当前版本。实际上,系统调用几乎从来没有变化
* (这将制造一场浩劫并且需要将所有的程序重新编译,因为系统调用是内核和进程的接口)。
*/
asmlinkage int our_sys_open(const char *filename,
int flags,
int mode)
{
int i = 0;
char ch;

/* 检查是否是我们要侦察的用户 */
if (uid == getuid_call()) {
/* getuid_call 是 getuid 系统调用,它给出调用我们的系统调用的进程的用户的UID。 */

/* 如果相关则报告文件 */
printk("Opened file by %d: ", uid);
do {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
get_user(ch, filename+i);
#else
ch = get_user(filename+i);
#endif
i++;
printk("%c", ch);
} while (ch != 0);
printk("\n");
}

/* 调用原始的 sys_open - 否则,我们将失去打开文件的能力 */
return original_call(filename, flags, mode);
}

/* 初始化模块 - 代替系统调用 */
int init_module()
{
/* 警告 - 现在可能太迟了,但可能对下次... */
printk("I'm dangerous. I hope you did a ");
printk("sync before you insmod'ed me.\n");
printk("My counterpart, cleanup_module(), is even");
printk("more dangerous. If\n");
printk("you value your file system, it will ");
printk("be \"sync; rmmod\" \n");
printk("when you remove this module.\n");

/* 将原始的函数指针保存在 original_call,然后用我们的our_sys_open代替系统调用表中的相应系统调用
*/
original_call = sys_call_table[__NR_open];
sys_call_table[__NR_open] = our_sys_open;

/* 为了得到系统调用foo的函数地址,使用 sys_call_table[__NR_foo] 。 */

printk("Spying on UID:%d\n", uid);

/* 得到 getuid 系统调用*/
getuid_call = sys_call_table[__NR_getuid];

return 0;
}

/* 清除 - 从/proc中注销相关的文件 */
void cleanup_module()
{
/* 将系统调用恢复原状 */
if (sys_call_table[__NR_open] != our_sys_open) {
printk("Somebody else also played with the ");
printk("open system call\n");
printk("The system may be left in ");
printk("an unstable state.\n");
}

sys_call_table[__NR_open] = original_call;
}

上一页