時間:2015/6/28來源:IT貓撲網(wǎng)作者:網(wǎng)管聯(lián)盟我要評論(0)
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/syscalls.h>
#include <asm/unistd.h>
#include <asm/uaccess.h>
#define MY_FILE "/root/LogFile"
char buf[128];
struct file *file = NULL;
static int __init init(void)
{
mm_segment_t old_fs;
printk("Hello, I'm the module that intends to write messages to file.\n");
if(file == NULL)
file = filp_open(MY_FILE, O_RDWR | O_APPEND | O_CREAT, 0644);
if (IS_ERR(file)) {
printk("error occured while opening file %s, exiting...\n", MY_FILE);
return 0;
}
sprintf(buf,"%s", "The Messages.");
old_fs = get_fs();
set_fs(KERNEL_DS);
file->f_op->write(file, (char *)buf, sizeof(buf), &file->f_pos);
set_fs(old_fs);
return 0;
}
static void __exit fini(void)
{
if(file != NULL)
filp_close(file, NULL);
}
module_init(init);
module_exit(fini);
MODULE_LICENSE("GPL");
其中:
typedef struct {
unsigned long seg;
} mm_segment_t;
#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFFUL)
#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
基本思想:
一個是要記得編譯的時候加上-D__KERNEL_SYSCALLS__
另外源文件里面要#include <linux/unistd.h>
如果報錯,很可能是因為使用的緩沖區(qū)超過了用戶空間的地址范圍。一般系統(tǒng)調用會要求你使用的緩沖區(qū)不能在內核區(qū)。這個可以用set_fs()、get_fs()來解決。在讀寫文件前先得到當前fs:
mm_segment_t old_fs=get_fs();
并設置當前fs為內核fs:set_fs(KERNEL_DS);
在讀寫文件后再恢復原先fs: set_fs(old_fs);
set_fs()、get_fs()等相關宏在文件include/asm/uaccess.h中定義。
個人感覺這個辦法比較簡單。
另外就是用flip_open函數(shù)打開文件,得到struct file *的指針fp。使用指針fp進行相應操作,如讀文件可以用fp->f_ops->read。最后用filp_close()函數(shù)關閉文件。 filp_open()、filp_close()函數(shù)在fs/open.c定義,在include/linux/fs.h中聲明。
解釋一點:
系統(tǒng)調用本來是提供給用戶空間的程序訪問的,所以,對傳遞給它的參數(shù)(比如上面的buf),它默認會認為來自用戶空間,在->write()函數(shù)中,為了保護內核空間,一般會用get_fs()得到的值來和USER_DS進行比較,從而防止用戶空間程序"蓄意"破壞內核空間;
而現(xiàn)在要在內核空間使用系統(tǒng)調用,此時傳遞給->write()的參數(shù)地址就是內核空間的地址了,在USER_DS之上(USER_DS ~ KERNEL_DS),如果不做任何其它處理,在write()函數(shù)中,會認為該地址超過了USER_DS范圍,所以會認為是用戶空間的"蓄意破壞",從而不允許進一步的執(zhí)行; 為了解決這個問題; set_fs(KERNEL_DS);將其能訪問的空間限制擴大到KERNEL_DS,這樣就可以在內核順利使用系統(tǒng)調用了!
補充:
我看了一下源碼,在include/asm/uaccess.h中,有如下定義:
#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF)
#define USER_DS MAKE_MM_SEG(PAGE_OFFSET)
#define get_ds() (KERNEL_DS)
#define get_fs() (current->addr_limit)
#define set_fs(x) (current->addr_limit = (x))
而它的注釋也很清楚:
/*
* The fs value determines whether argument validity checking should be
* performed or not. If get_fs() == USER_DS, checking is performed, with
* get_fs() == KERNEL_DS, checking is bypassed.
*
* For historical reasons, these macros are grossly misnamed.
*/
因此可以看到,fs的值是作為是否進行參數(shù)檢查的標志。系統(tǒng)調用的參數(shù)要求必須來自用戶空間,所以,當在內核中使用系統(tǒng)調用的時候,set_fs(get_ds())改變了用戶空間的限制,即擴大了用戶空間范圍,因此即可使用在內核中的參數(shù)了。
關鍵詞標簽:linux內核
相關閱讀
熱門文章 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程使用screen管理你的遠程會話GNU/Linux安裝vmware如何登錄linux vps圖形界面 Linux遠程桌面連
人氣排行 Linux下獲取CPUID、硬盤序列號與MAC地址linux tc實現(xiàn)ip流量限制dmidecode命令查看內存型號linux下解壓rar文件安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程Ubuntu linux 關機、重啟、注銷 命令lcx.exe、nc.exe、sc.exe入侵中的使用方法查看linux服務器硬盤IO讀寫負載