因為原本參考的資料其例子有錯,所以特此列出來修正,同時說明實作系統呼叫的方法。
原本的例子 (syscall.c): http://www.tldp.org/LDP/lkmpg/2.6/html/x978.html
編譯錯誤的訊息:
# syscall.c: In function "our_sys_open":
# syscall.c:86: error: "struct task_struct" has no member named "uid"
錯誤的原因是因為原本定義程式使用者相關資訊的結構已經重新定義到 "linux/cred.h" 中,所已成是要加上 "#include <linux/cred.h>" 並使用 "current_uid()" 來取得使用者資訊。
這個範例的功能是用來監督特定的使用者,當他執行開啟檔案 (sys_open) 的動作時,就輸出檔案名稱的訊息。當 kernel module 載入時 (init_module),sys_call_table 中原本的開檔系統呼叫被我們自己的 our_sys_open 函數所取代。而在 our_sys_open 函數中,若開檔的正是指定的使用者,則透過 printk 印出訊息。最後在卸載 kernel module 時 (cleanup_module),將原本 sys_call_table 的內容還元回去。
/*
* syscall.c
*
* System call "stealing" sample.
*
* Copyright (C) 2001 by Peter Jay Salzman
*/
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module, */
#include <linux/moduleparam.h> /* which will have params */
#include <linux/unistd.h> /* The list of system calls */
/*
* For the current (process) structure, we need
* this to know who the current user is.
*/
#include <linux/sched.h>
#include <linux/cred.h>
#include <asm/uaccess.h>
extern void *sys_call_table[];
/*
* UID we want to spy on - will be filled from the
* command line
*/
static int uid;
module_param(uid, int, 0644);
asmlinkage int (*original_call) (const char *, int, int);
asmlinkage int our_sys_open(const char *filename, int flags, int mode)
{
int i = 0;
char ch;
/*
* Check if this is the user we're spying on
*/
if (uid == current_uid()) {
/*
* Report the file, if relevant
*/
printk("Opened file by %d: ", uid);
do {
get_user(ch, filename + i);
i++;
printk("%c", ch);
} while (ch != 0);
printk("\n");
}
/*
* Call the original sys_open - otherwise, we lose
* the ability to open files
*/
return original_call(filename, flags, mode);
}
/*
* Initialize the module - replace the system call
*/
int init_module()
{
/*
* Warning - too late for it now, but maybe for
* next time...
*/
printk(KERN_ALERT "I'm dangerous. I hope you did a ");
printk(KERN_ALERT "sync before you insmod'ed me.\n");
printk(KERN_ALERT "My counterpart, cleanup_module(), is even");
printk(KERN_ALERT "more dangerous. If\n");
printk(KERN_ALERT "you value your file system, it will ");
printk(KERN_ALERT "be \"sync; rmmod\" \n");
printk(KERN_ALERT "when you remove this module.\n");
/*
* Keep a pointer to the original function in
* original_call, and then replace the system call
* in the system call table with our_sys_open
*/
original_call = sys_call_table[__NR_open];
sys_call_table[__NR_open] = our_sys_open;
/*
* To get the address of the function for system
* call foo, go to sys_call_table[__NR_foo].
*/
printk(KERN_INFO "Spying on UID:%d\n", uid);
return 0;
}
/*
* Cleanup - unregister the appropriate file from /proc
*/
void cleanup_module()
{
/*
* Return the system call back to normal
*/
if (sys_call_table[__NR_open] != our_sys_open) {
printk(KERN_ALERT "Somebody else also played with the ");
printk(KERN_ALERT "open system call\n");
printk(KERN_ALERT "The system may be left in ");
printk(KERN_ALERT "an unstable state.\n");
}
sys_call_table[__NR_open] = original_call;
}