diff --git a/study/engine/2.6.18/memoryEngine.c b/study/engine/2.6.18/memoryEngine.c new file mode 100644 index 0000000..3ef8a28 --- /dev/null +++ b/study/engine/2.6.18/memoryEngine.c @@ -0,0 +1,1070 @@ +/* +* Author: HIT CS HDMC team. +* Create: 2010-3-12 8:50 +* Last modified: 2010-6-13 14:06:20 +* Description: +* Memory fault injection engine running as a kernel module. +* This module will create "/proc/memoryEngine/" directory and 9 proc nodes. +* Write paramenters and request to these proc nodes and read the output from related proc node. +*/ + +#include "memoryEngine.h" + +/* +* proc entries +*/ +struct proc_dir_entry *dir = NULL; /// the directory of the MEMORY INJECT Moudle +struct proc_dir_entry *proc_pid = NULL; /// write only +struct proc_dir_entry *proc_va = NULL; /// write only +struct proc_dir_entry *proc_ctl = NULL; /// write only +struct proc_dir_entry *proc_kFuncName = NULL; /// write only +struct proc_dir_entry *proc_val = NULL; /// rw +struct proc_dir_entry *proc_signal = NULL; /// rw +struct proc_dir_entry *proc_pa = NULL; /// read only +struct proc_dir_entry *proc_taskINfo = NULL; /// read only + +/* +* proc node values +*/ +int pid; /// pid +unsigned long va; /// virtual Address +unsigned long pa; /// physical Addreess +int ctl; /// ctl +int signal; /// signal +char kFuncName[MAX_LINE]; /// kFuncName +long memVal; /// memVal + +unsigned long ack_pa; /// physical Address +unsigned long ack_va; /// virtual Address +int ack_signal; /// signal +int ret; /// return value +char taskInfo[PAGE_SIZE]; /// taskInfo + +/////////////////////////////////////////////// + +unsigned long userspace_phy_mem; /// user space physical memory +long orig_pa_data; /// origin data of the physics memory +long new_pa_data; /// the new data you want write to physics memory + +int faultInterval; + +/* +* kprobe +*/ +static struct kprobe kp_kFunc; + +struct jprobe jprobe1 = +{ + .entry = jforce_sig_info, + .kp = + { + .symbol_name = "force_sig_info", + }, +}; + +//时钟中断数计数 +static int count = 0; + +//保存原始代码 +static long orig_code = 0; + +/* +* process the request +*/ +void do_request(void) +{ + struct task_struct *task = NULL; + unsigned long pa = 0; + long kernel_va = 0; + int status; + + /// get a task's memory map information + if(ctl == REQUEST_TASK_INFO) + { + dbginfo("Rcv request:Get task info\n"); + + memset(taskInfo,'\0',sizeof(taskInfo)); + + if(pid <= 0) + { + ack_signal = ACK_TASK_INFO; + return; + } + task = findTaskByPid(pid); + + if( task != NULL ) + { + getTaskInfo(task, taskInfo, sizeof(taskInfo)); + } + ack_signal = ACK_TASK_INFO; + + return; + } + /// convert a process's linear address to physical address + else if(ctl == REQUEST_V2P) + { + task = findTaskByPid(pid); + if( task == NULL ) + { + dbginfo("No such process\n"); + ack_pa = -1; + ack_signal = ACK_V2P; + return; + } + if( task->mm == NULL ) + { + ack_pa = -1; + ack_signal = ACK_V2P; + return; + } + ack_pa = v2p(task->mm,va,&status); + if(ack_pa == FAIL) + { + dbginfo("No physical address\n"); + } + ack_signal = ACK_V2P; + return; + } + /// convert kernel virtual address to physical address + else if(ctl == REQUEST_KV2P) + { + ack_pa = kv2p(va,&status); + if(pa == FAIL) + { + dbginfo("No physical address\n"); + } + ack_signal = ACK_KV2P; + return; + } + /// get kernel function's addr(kernel virtual address) + else if(ctl == REQUEST_KFUNC_VA) + { + ack_va = kFunc2v(kFuncName); + ack_signal = ACK_KFUNC_VA; + return; + } + /// 请求读取内核函数起始地址内容 + else if(ctl == REQUEST_READ_KFUNC) + { + kernel_va = kFunc2v(kFuncName); + memVal = *((long *)kernel_va); + ack_signal = ACK_READ_KFUNC; + } + /// 请求改写内核函数起始地址内容 + else if(ctl == REQUEST_WRITE_KFUNC) + { + //利用kprobe,在第一次调用do_timer()时,注入故障 + int ret; + count = 0; + if(strlen(kFuncName) > 0) + { + faultInterval = 1; //故障仅持续一个时钟周期 + kp_kFunc.addr = 0; + kp_kFunc.symbol_name = kFuncName; + kp_kFunc.pre_handler = handler_pre_kFunc; + ret = register_kprobe(&kp_kFunc); + if(ret < 0) + { + dbginfo("Fained to register kprobe\n"); + ack_signal = ACK_WRITE_KFUNC; + return; + } + + //等待故障注入结束 + dbginfo("start count\n"); + int temp=0; + while(1) + { + if(count == -1) + { + unregister_kprobe(&kp_kFunc); + dbginfo("recovery\n"); + break; + } + if(temp == -1) + { + break; + } + temp++; + //dbginfo("count:%d\n",count); + } + } + ack_signal = ACK_WRITE_KFUNC; + dbginfo("Success to inject MTTR fault\n"); + return; + } + +} + +/* +* get a task's memory map information +*/ +int getTaskInfo(struct task_struct *pTask, char *pData, int length) +{ + struct mm_struct *pMM; + struct vm_area_struct *pVMA; + struct vm_area_struct *p; + char file[MAX_LINE]; + struct dentry *pPath = NULL; + char *end, *start; + char *info = pData; + + long phy_addr; + unsigned long start_va,end_va; + int status; + + if(pTask == NULL) { return FAIL; } + if((pMM = pTask->mm) == NULL) { return FAIL; } + + memset(pData, '\0', length); + //前19个字段是关于进程内存信息的总体信息 + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->total_vm, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->locked_vm, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->shared_vm, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->exec_vm, DELIMITER); + + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->stack_vm, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->reserved_vm, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->def_flags, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->nr_ptes, DELIMITER); + + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->start_code, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->end_code, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->start_data, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->end_data, DELIMITER); + + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->start_brk, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->brk, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->start_stack, DELIMITER); + + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->arg_start, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->arg_end, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->env_start, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->env_end, DELIMITER); + + pVMA = pMM->mmap; + if(pVMA == NULL) { return OK; } + for(p=pVMA; p!=NULL; p=p->vm_next) + { + //起始地址 + safe_sprintf(pData, length, info+strlen(info), "%lx %lx ", p->vm_start, p->vm_end); + //属性 + if(p->vm_flags & VM_READ) + { safe_sprintf(pData, length, info+strlen(info), "r"); } + else + { safe_sprintf(pData, length, info+strlen(info), "-"); } + + if(p->vm_flags & VM_WRITE) + { safe_sprintf(pData, length, info+strlen(info), "w"); } + else + { safe_sprintf(pData, length, info+strlen(info), "-"); } + + if(p->vm_flags & VM_EXEC) + { safe_sprintf(pData, length, info+strlen(info), "x"); } + else + { safe_sprintf(pData, length, info+strlen(info), "-"); } + + if(p->vm_flags & VM_SHARED) + { safe_sprintf(pData, length, info+strlen(info), "s"); } + else + { safe_sprintf(pData, length, info+strlen(info), "p"); } + + //对应文件名 + if(p->vm_file != NULL) + { + if(p->vm_file->f_dentry != NULL) + { + safe_sprintf(pData, length, info+strlen(info), " "); + memset(file,'\0',sizeof(file)); + for(pPath = p->vm_file->f_dentry; pPath != NULL; pPath = pPath->d_parent) + { + if(strcmp(pPath->d_name.name,"/") != 0) + { + strcpy(file + strlen(file), pPath->d_name.name); + strcpy(file + strlen(file), "/"); + continue; + } + break; + } + do + { + end = file + strlen(file) - 1; + for(start = end - 1; *start != '/' && start > file; start--); + if(*start == '/') {start++;} + *end = '\0'; + + safe_sprintf(pData, length, info+strlen(info), "/%s", start); + *start = '\0'; + } while(start > file); + } + } + safe_sprintf(pData, length, info+strlen(info), "%c", DELIMITER); + + //对应物理地址页 + start_va = p->vm_start; + end_va = p->vm_end; + while(end_va > start_va) + { + safe_sprintf(pData, length, info+strlen(info), "%lx-%lx\t", start_va, start_va + PAGE_SIZE); + phy_addr = v2p(pMM, start_va, &status); + if(phy_addr != FAIL) + { + safe_sprintf(pData, length, info+strlen(info), "va:0x%lx <--> pa:0x%lx", start_va, phy_addr); + } + start_va += PAGE_SIZE; + safe_sprintf(pData, length, info+strlen(info), "%c", DELIMITER); + } + + safe_sprintf(pData, length, info+strlen(info), "%c", DELIMITER); + } + return OK; +} + +/* +* +*/ +static int handler_pre_kFunc(struct kprobe *p, struct pt_regs *regs) +{ + unsigned long va; + va = (unsigned long)p->addr; + if(va <= 0) { return OK; } + + //第一次触发 + if(count == 0) + { + //读取前64字节,注入故障 + orig_code = *((long *)va); + //_inject_fault(va,memVal); + *((long *)va) = memVal; //故障 + return OK; + } + count ++; + //到达结束时间 + if(count == faultInterval + 1) + { + //恢复code + *((long *)va) = orig_code; + count = -1; + } + return OK; +} + +/* +* find_task_by_pid maybe not supported +* O(n) is fine :) +*/ +struct task_struct * findTaskByPid(pid_t pid) +{ + struct task_struct *task = NULL; + + // Traversing the process in the system to find the PID + // add by gatieme @2016-03-20 + for_each_process(task) + { + if(task->pid == pid) + { + return task; + } + } + return NULL; +} + +/* +* convert a process's linear address to physical address +*/ +long v2p(struct mm_struct *pMM,unsigned long va,int *pStatus) +{ + pte_t *pte = NULL; + unsigned long phyaddress = FAIL; + + pte = getPte(pMM, va); + if(pte != NULL) + { + phyaddress = (pte_val(*pte) & PAGE_MASK) | (va & ~PAGE_MASK); + } + return phyaddress; +} + +/* +* convert kernel virtual address to physical address +*/ +long kv2p(unsigned long va,int *pStatus) +{ + if(va < 0) + return FAIL; + if(__pa(va) >= 0) + return __pa(va); + return FAIL; +} + +/* +* get kernel function's addr(kernel virtual address) +* the kernel function should be looked up in the System.map +*/ +static struct kprobe kp; +long kFunc2v(char *funcName) +{ + int ret; + unsigned long va; + + kp.addr = 0; + kp.symbol_name = funcName; + ret = register_kprobe(&kp); + if(ret < 0) + { + dbginfo("Fained to register kprobe\n"); + return FAIL; + } + va = (unsigned long)kp.addr; + unregister_kprobe(&kp); + if(va == 0) + return FAIL; + return va; +} + + + +/* +* +*/ +struct vm_area_struct * getVMA(struct mm_struct *pMM,unsigned long va) +{ + struct vm_area_struct *p; + if(pMM == NULL) return NULL; + p = pMM->mmap; + if(p == NULL) return NULL; + + for(; p != NULL; p = p->vm_next) + { + if( va >= p->vm_start && va < p->vm_end ) + { + return p; + } + } + return NULL; +} + +/* +* +*/ +pte_t * getPte(struct mm_struct *pMM, unsigned long va) +{ + pgd_t *pgd = NULL; + pmd_t *pmd = NULL; + pud_t *pud = NULL; + pte_t *pte = NULL; + + ///get the pdg entry pointer + pgd = pgd_offset(pMM, va); + if(pgd_none(*pgd)) { return NULL; } + + pud = pud_offset(pgd,va); + if(pud_none(*pud)) { return NULL; } + + pmd = pmd_offset(pud,va); + if(pmd_none(*pmd)) { return NULL; } + + pte = pte_offset_kernel(pmd,va); + if(pte_none(*pte)) { return NULL; } + if(!pte_present(*pte)) { return NULL; } + return pte; +} + +/* +* +*/ +int setVMAFlags(struct mm_struct *pMM,unsigned long va,int *pStatus,int flags) +{ + struct vm_area_struct *p; + p = getVMA(pMM,va); + if(p == NULL) return FAIL; + + if(flags > 0) + { + p->vm_flags |= VM_WRITE; + p->vm_flags |= VM_SHARED; + } + if(flags == 0) + { + p->vm_flags &= ~VM_WRITE; + p->vm_flags &= ~VM_SHARED; + } + else { return FAIL; } + return OK; +} + +/* +* +*/ +int setPageFlags(struct mm_struct *pMM,unsigned long va,int *pStatus,int flags) +{ + pte_t *pte = NULL; + pte_t ret; + pte = getPte(pMM, va); + if( pte == NULL ) { return FAIL; } + if(flags > 0) + { + ret = pte_mkwrite(*pte); + } + else if(flags == 0) + { + ret = pte_wrprotect(*pte); + } + else { return FAIL; } + return OK; +} + +/* +* +*/ +int proc_write_pid( struct file *file, + const char __user *buffer, + unsigned long count, + void * data) +{ + int iRet; + char sPid[MAX_LINE]; + + if(count <= 0) + { + return FAIL; + } + + memset(sPid, '\0', sizeof(sPid)); + ///////////////////////////////////////////////////////////////////// + // + // copy_from_user函数的目的是从用户空间拷贝数据到内核空间, + // 失败返回没有被拷贝的字节数,成功返回0. + // 这么简单的一个函数却含盖了许多关于内核方面的知识, + // 比如内核关于异常出错的处理. + // 从用户空间拷贝数据到内核中时必须很小心, + // 假如用户空间的数据地址是个非法的地址,或是超出用户空间的范围, + // 或是那些地址还没有被映射到,都可能对内核产生很大的影响, + // 如oops,或被造成系统安全的影响. + // 所以copy_from_user函数的功能就不只是从用户空间拷贝数据那样简单了, + // 他还要做一些指针检查连同处理这些问题的方法. + // + // 函数原型在[arch/i386/lib/usercopy.c]中 + // unsigned long + // copy_from_user( void *to, + // const void __user *from, + // unsigned long n) + // + ///////////////////////////////////////////////////////////////////// + // + // 将用户空间中, 地址buffr指向的count个数据拷贝到内核空间地址sPid中 + iRet = copy_from_user(sPid, buffer, count); + if(iRet != 0) + { + dbginfo("Error when copy_from_user...\n"); + return FAIL; + } + + iRet = sscanf(sPid, "%d", &pid); // 将读出来的数据sPid赋值给模块的全局变量pid + if(iRet != 1) + { + return FAIL; + } + dbginfo("Rcv pid:%d\n",pid); + + return count; +} + +/* +* +*/ +int proc_read_virtualAddr( char * page, + char **start, + off_t off, + int count, + int * eof, + void * data) +{ + int iLen; + + iLen = sprintf(page, "%lx", ack_va); + + + return iLen; +} + +/* +* +*/ +int proc_write_virtualAddr( struct file *file, + const char *buffer, + unsigned long count, + void * data) +{ + int iRet; + char sVa[MAX_LINE]; + + if(count <= 0) + { + return FAIL; + } + + memset(sVa, '\0', sizeof(sVa)); + + iRet = copy_from_user(sVa, buffer, count); + if(iRet) + { + return FAIL; + } + + iRet = sscanf(sVa,"%lx",&va); + if(iRet != 1) + { + return FAIL; + } + + dbginfo("Rcv virtual addr:0x%lx\n",va); + + return count; +} + +/* +* +*/ +int proc_write_ctl( struct file *file, + const char *buffer, + unsigned long count, + void * data) +{ + int iRet; + char sCtl[MAX_LINE]; + + if(count <= 0) + { + return FAIL; + } + + memset(sCtl, '\0', sizeof(sCtl)); + + iRet = copy_from_user(sCtl, buffer, count); + if(iRet) + { + return FAIL; + } + + iRet = sscanf(sCtl,"%d",&ctl); + if(iRet != 1) + { + return FAIL; + } + + do_request(); + + return count; +} + +/* +* +*/ +int proc_read_signal( char * page, + char **start, + off_t off, + int count, + int * eof, + void * data) +{ + int iLen; + iLen = sprintf(page, "%d", ack_signal); + return iLen; +} + +/* +* +*/ +int proc_write_signal( struct file *file, + const char *buffer, + unsigned long count, + void * data) +{ + int iRet; + char sSignal[MAX_LINE]; + + if(count <= 0) + { + return FAIL; + } + + memset(sSignal, '\0', sizeof(sSignal)); + iRet = copy_from_user(sSignal, buffer, count); + if(iRet) + { + return FAIL; + } + + iRet = sscanf(sSignal,"%d",&signal); + if(iRet != 1) + { + return FAIL; + } + + dbginfo("Rcv signal:%d\n",signal); + + return count; +} + +/* +* +*/ +int proc_read_pa(char * page,char **start, off_t off, int count, int * eof,void * data) +{ + int iLen; + iLen = sprintf(page, "%lx", ack_pa); + return iLen; +} + +/* +* +*/ +int proc_write_pa(struct file *file,const char *buffer,unsigned long count,void * data) +{ + int iRet; + char sPa[MAX_LINE]; + + if(count <= 0) { return FAIL; } + memset(sPa, '\0', sizeof(sPa)); + iRet = copy_from_user(sPa, buffer, count); + if(iRet) { return FAIL; } + iRet = sscanf(sPa,"%lx",&pa); + if(iRet != 1) { return FAIL; } + dbginfo("Rcv pa:0x%lx\n",pa); + return count; +} + +/* +* +*/ +int proc_write_kFuncName(struct file *file,const char *buffer,unsigned long count,void * data) +{ + int iRet; + if(count <= 0) { return FAIL; } + memset(kFuncName, '\0', sizeof(kFuncName)); + iRet = copy_from_user(kFuncName, buffer, count); + if(iRet) { return FAIL; } + //remove '\n' + if(kFuncName[strlen(kFuncName) - 1] == '\n') + { + kFuncName[strlen(kFuncName) - 1] = '\0'; + } + dbginfo("Rcv kernel func name:%s\n",kFuncName); + return count; +} + +/* +* +*/ +int proc_read_taskInfo(char * page,char **start, off_t off, int count, int * eof,void * data) +{ + int iLen; + iLen = sprintf(page, "%s", taskInfo); + return iLen; +} + +/* +* +*/ +int proc_write_memVal(struct file *file,const char *buffer,unsigned long count,void * data) +{ + int iRet; + char sMemVal[MAX_LINE]; + + if(count <= 0) + { + return FAIL; + } + + memset(sMemVal, '\0', sizeof(sMemVal)); + iRet = copy_from_user(sMemVal, buffer, count); + if(iRet) + { + return FAIL; + } + + iRet = sscanf(sMemVal,"%lx",&memVal); + if(iRet != 1) + { + return FAIL; + } + + dbginfo("Rcv memVal:0x%lx\n",memVal); + return count; +} + +/* +* +*/ +int proc_read_memVal( char * page, + char **start, + off_t off, + int count, + int * eof, + void * data) +{ + int iLen; + iLen = sprintf(page, "%lx", memVal); + return iLen; +} + +/* +* init memory fault injection module +* 初始化内存注入故障模块 +* +* 使用proc_mkdir()创建一个dir = /proc/memoryEngine +* 再利用create_proc_read_entry()函数创建一个processinfo文件。 +* 我们从模块里面获取的信息都将写入到这些文件中。 +* +*/ +static int __init initME(void) +{ + /* + * create a direntory named "memoryEngine" in /proc for the moudles + * as the interface between the kernel and the user program. + * + */ + dir = proc_mkdir("memoryEngine", NULL); + if(dir == NULL) + { + dbginfo("Can't create /proc/memoryEngine/\n"); + return FAIL; + } + dir->owner = THIS_MODULE; + + /// create a file named "pid" in direntory + proc_pid = create_proc_entry("pid", PERMISSION, dir); + if(proc_pid == NULL) + { + dbginfo("Can't create /proc/memoryEngine/pid\n"); + + remove_proc_entry("memoryEngine", NULL); + + return FAIL; + } + proc_pid->write_proc = proc_write_pid; /// write only + proc_pid->owner = THIS_MODULE; + + + /// create a file named "virtualAddr" in direntory + proc_va = create_proc_entry("virtualAddr", PERMISSION, dir); + if(proc_va == NULL) + { + dbginfo("Can't create /proc/memoryEngine/virtualAddr\n"); + + remove_proc_entry("pid", dir); + remove_proc_entry("memoryEngine", NULL); + + return FAIL; + } + proc_va->read_proc = proc_read_virtualAddr; // can read + proc_va->write_proc = proc_write_virtualAddr; // can write + proc_va->owner = THIS_MODULE; + + /// create a file named "ctl" in direntory + proc_ctl = create_proc_entry("ctl", PERMISSION, dir); + if(proc_ctl == NULL) + { + dbginfo("Can't create /proc/memoryEngine/ctl\n"); + + remove_proc_entry("pid", dir); + remove_proc_entry("virtualAddr", dir); + remove_proc_entry("memoryEngine", NULL); + + return FAIL; + } + proc_ctl->write_proc = proc_write_ctl; // write only + proc_ctl->owner = THIS_MODULE; + + /// create a file named "signal" in direntory + proc_signal = create_proc_entry("signal", PERMISSION, dir); + if(proc_signal == NULL) + { + dbginfo("Can't create /proc/memoryEngine/signal\n"); + + remove_proc_entry("pid", dir); + remove_proc_entry("virtualAddr", dir); + remove_proc_entry("ctl", dir); + remove_proc_entry("memoryEngine", NULL); + + return FAIL; + } + proc_signal->read_proc = proc_read_signal; // can read + proc_signal->write_proc = proc_write_signal; // can write + proc_signal->owner = THIS_MODULE; + + /// create a file named "physicalAddr" in direntory + proc_pa = create_proc_entry("physicalAddr", PERMISSION, dir); + if(proc_pa == NULL) + { + dbginfo("Can't create /proc/memoryEngine/physicalAddr\n"); + + remove_proc_entry("pid", dir); + remove_proc_entry("virtualAddr", dir); + remove_proc_entry("ctl", dir); + remove_proc_entry("memoryEngine", NULL); + + return FAIL; + } + + proc_pa->read_proc = proc_read_pa; // can read + proc_pa->write_proc = proc_write_pa; // can write + + + /// create a file named "kFuncName" in direntory + proc_kFuncName = create_proc_entry("kFuncName", PERMISSION, dir); + if(proc_kFuncName == NULL) + { + dbginfo("Can't create /proc/memoryEngine/kFuncName\n"); + + remove_proc_entry("pid", dir); + remove_proc_entry("virtualAddr", dir); + remove_proc_entry("ctl", dir); + remove_proc_entry("physicalAddr", dir); + remove_proc_entry("memoryEngine", NULL); + + return FAIL; + } + proc_kFuncName->write_proc = proc_write_kFuncName; // write only + + + /// create a file named "taskInfo" in direntory + proc_taskINfo = create_proc_entry("taskInfo", PERMISSION, dir); + if(proc_taskINfo == NULL) + { + dbginfo("Can't create /proc/memoryEngine/taskInfo\n"); + + remove_proc_entry("pid", dir); + remove_proc_entry("virtualAddr", dir); + remove_proc_entry("ctl", dir); + remove_proc_entry("physicalAddr", dir); + remove_proc_entry("kFuncName", dir); + remove_proc_entry("memoryEngine", NULL); + + return FAIL; + } + proc_taskINfo->read_proc = proc_read_taskInfo; // read only + + /// create a file named "memVal" in direntory + proc_val = create_proc_entry("memVal", PERMISSION, dir); + if(proc_val == NULL) + { + dbginfo("Can't create /proc/memoryEngine/memVal\n"); + + remove_proc_entry("pid", dir); + remove_proc_entry("virtualAddr", dir); + remove_proc_entry("ctl", dir); + remove_proc_entry("physicalAddr", dir); + remove_proc_entry("kFuncName", dir); + remove_proc_entry("taskInfo", dir); + remove_proc_entry("memoryEngine", NULL); + + return FAIL; + } + proc_val->write_proc = proc_write_memVal; // can write + proc_val->read_proc = proc_read_memVal; // can read + + + ret = register_jprobe(&jprobe1); + if (ret < 0) + { + printk("register_jprobe jprobe1 failed, returned %d\n", ret); + return ret; + } + printk("Planted jprobe at force_sig_info: %p\n", jprobe1.kp.addr); + + dbginfo("Memory engine module init\n"); + return OK; +} + + +static int jforce_sig_info(int sig,struct siginfo *info,struct task_struct *t) +{ + printk("MemSysFI: kernel is sending signal %d to process pid: %d, comm: %s\n",sig,t->pid,t->comm); +/* + if (f_inject == 'N') + { + jprobe_return(); + return 0; + } + + down_interruptible(&sem); + if ( addone(addone(inj_info.rear))==inj_info.front ) + { + */ + /*error:队列满*/ + /* + sprintf(inj_info.inj_log[inj_info.rear].msg,"caution : buf is full, messages have been dropped\n"); + } + else + { + inj_info.rear = addone(inj_info.rear); + sprintf(inj_info.inj_log[inj_info.rear].msg,"warning : kernel is sending signal %d to process pid: %d, comm: %s\n",sig,current->pid,current->comm); + //inj_info->inj_log[inj_info->rear ] = x ; + } + up(&sem); + */ + /* + if(message!=NULL) + { + for(i=0;i<256;i++) + message[i]='\0'; + + sprintf(message,"warning : kernel is sending signal %d to process pid: %d, comm: %s\n\0",sig,current->pid,current->comm); + } + else + return -1; + + + struct bufferList *buflist; + buflist = (struct bufferList *)kmalloc(sizeof(struct bufferList),GFP_KERNEL); + buflist->pNext = NULL; + buflist->buffer = message; + + down_interruptible(&sem); + if(Head==NULL) + { + Head = buflist; + Tail = Head; + } + else + { + Tail->pNext = buflist; + Tail = buflist; + } + flag = 1; + up(&sem); + */ + +// wake_up_interruptible(&wq2); + + jprobe_return(); + return 0; +} + +/* +* uninit memory fault injection module +*/ +static void __exit exitME(void) +{ + remove_proc_entry("pid", dir); + remove_proc_entry("virtualAddr", dir); + remove_proc_entry("ctl", dir); + remove_proc_entry("signal", dir); + remove_proc_entry("physicalAddr", dir); + remove_proc_entry("kFuncName", dir); + remove_proc_entry("taskInfo", dir); + remove_proc_entry("memVal", dir); + remove_proc_entry("memoryEngine", NULL); + unregister_jprobe(&jprobe1); + printk("jprobe at %p unregistered.\n", jprobe1.kp.addr); + dbginfo("Memory engine module exit\n"); +} + +module_init(initME); +module_exit(exitME); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("HIT CS HDMC team"); +MODULE_DESCRIPTION("Memory Engine Module."); + diff --git a/study/engine/2.6.18/memoryEngine.h b/study/engine/2.6.18/memoryEngine.h new file mode 100644 index 0000000..f13d074 --- /dev/null +++ b/study/engine/2.6.18/memoryEngine.h @@ -0,0 +1,126 @@ +/* +* Author: HIT CS HDMC team. +* Create: 2010-3-12 8:20:01 +* Last modified: 2010-6-13 14:13:47 +*/ + +#ifndef _MEMORY_ENGINE_H +#define _MEMORY_ENGINE_H + +/* +* common include header files +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_LINE 256 /// max length of a line +#define DELIMITER '\n' /// the char is used to split the taskinfo +#define PERMISSION 0644 /// proc node permission +/* +* return values +*/ +#define OK 0 +#define FAIL -1 +#define PGD_NONE -2 +#define PUD_NONE -3 +#define PMD_NONE -4 +#define PTE_NONE -5 +#define PTE_NOT_PRESENT -6 + + + +/* +* request command +*/ +#define REQUEST_TASK_INFO 1 /// get a task's memory map information +#define REQUEST_V2P 2 /// convert a process's linear address to physical address +#define REQUEST_KV2P 3 /// convert kernel virtual address to physical address +#define REQUEST_KFUNC_VA 4 /// get kernel function's addr(kernel virtual address) +#define REQUEST_READ_KFUNC 5 /// 璇锋眰璇诲彇鍐呮牳鍑芥暟璧峰鍦板潃鍐呭 +#define REQUEST_WRITE_KFUNC 6 /// 璇锋眰鏀瑰啓鍐呮牳鍑芥暟璧峰鍦板潃鍐呭 +///#define REQUEST_WRITE 10 /// 璇锋眰鏀瑰啓鎸囧畾鐗╃悊鍦板潃鍐呭锛屾敼涓虹敤鎴锋佸疄鐜版鍔熻兘 +///#define REQUEST_MEM 11 /// 璇锋眰鑾峰彇鍏ㄩ儴鐗╃悊鍐呭瓨淇℃伅 +///#define REQUEST_ADDR_STOP 12 /// + +/* +* ack signals +*/ +#define ACK_TASK_INFO REQUEST_TASK_INFO +#define ACK_V2P REQUEST_V2P +#define ACK_KV2P REQUEST_KV2P +#define ACK_KFUNC_VA REQUEST_KFUNC_VA +#define ACK_READ_KFUNC REQUEST_READ_KFUNC +#define ACK_WRITE_KFUNC REQUEST_WRITE_KFUNC +///#define REQUEST_WRITE REQUEST_WRITE +///#define ACK_MEM REQUEST_MEM +///#define ACK_ADDR_STOP REQUEST_ADDR_STOP + +/* +* #define DEBUG ,dbginfo() will add more debug information into nomal printk. +* #define SILENCE ,dbginfo() will print nothing. +* Otherwise ,dbginfo() equals to printk. +*/ +#ifdef __FUNCTION__ +#ifdef __LINE__ + #ifdef DEBUG + //printk with line and function name + #define dbginfo(format,args...); \ + printk(KERN_INFO "%s-L%d:"format,__FUNCTION__,__LINE__,##args); + #elif defined SILENCE + #define dbginfo(format,args...); + #else //printk normally + #define dbginfo(format,args...); printk(KERN_INFO format,##args); + #endif +#endif +#endif + +/* +* safe sprintf +* It will not be out of range. +*/ +#define safe_sprintf(start, n, p, format, args...); \ + { if( (p - start) < n ) { snprintf( (char *)p, (n - (p - start)), format, ##args ); } } + + +/* +* utility functions +*/ +static int handler_pre_kFunc(struct kprobe *p, struct pt_regs *regs); +struct task_struct *findTaskByPid(pid_t pid); +long v2p(struct mm_struct *pMM,unsigned long va,int *pStatus); +long kv2p(unsigned long va,int *pStatus); +long kFunc2v(char *funcName); +struct vm_area_struct * getVMA(struct mm_struct *pMM,unsigned long va); +pte_t * getPte(struct mm_struct *pMM,unsigned long va); +int setVMAFlags(struct mm_struct *pMM,unsigned long va,int *pStatus,int flags); +int setPageFlags(struct mm_struct *pMM,unsigned long va,int *pStatus,int flags); +int getTaskInfo(struct task_struct *pTask, char *pData, int length); + +/* +* proc entry function +*/ +int proc_write_pid(struct file *file,const char __user *buffer,unsigned long count,void * data); +int proc_read_virtualAddr(char * page,char **start, off_t off, int count, int * eof,void * data); +int proc_write_virtualAddr(struct file *file,const char *buffer,unsigned long count,void * data); +int proc_write_ctl(struct file *file,const char *buffer,unsigned long count,void * data); +int proc_read_signal(char * page,char **start, off_t off, int count, int * eof,void * data); +int proc_write_signal(struct file *file,const char *buffer,unsigned long count,void * data); +int proc_read_pa(char * page,char **start, off_t off, int count, int * eof,void * data); +static int jforce_sig_info(int sig,struct siginfo *info,struct task_struct *t); +#endif + diff --git a/study/engine/Makefile b/study/engine/Makefile new file mode 100644 index 0000000..f3ab123 --- /dev/null +++ b/study/engine/Makefile @@ -0,0 +1,36 @@ +# Makefile for the memory fault injection engine. +# +# Author: HIT CS HDMC team. +# Create: 2010-3-12 8:46 +# Last modified: 2010-6-13 13:55:29 +# Description: +# This program is loaded as a kernel(v2.6.18 or later) module. +# Use "make install" to load it into kernel. +# Use "make remove" to remove the module out of kernel. +# + +ifneq ($(KERNELRELEASE),) + +obj-m := memoryEngine.o + +else + +obj-m := memoryEngine.o + +KERNELDIR=/lib/modules/$(shell uname -r)/build + +PWD=$(shell pwd) + +all: + make -C $(KERNELDIR) M=$(PWD) modules +install: + insmod memoryEngine.ko + +remove: + rmmod memoryEngine + +clean: + make -C /lib/modules/`uname -r`/build M=`pwd` clean + rm -f modules.order Module.symvers Module.markers + +endif diff --git a/study/engine/arm64/memoryEngine.c b/study/engine/arm64/memoryEngine.c new file mode 100644 index 0000000..3ef8a28 --- /dev/null +++ b/study/engine/arm64/memoryEngine.c @@ -0,0 +1,1070 @@ +/* +* Author: HIT CS HDMC team. +* Create: 2010-3-12 8:50 +* Last modified: 2010-6-13 14:06:20 +* Description: +* Memory fault injection engine running as a kernel module. +* This module will create "/proc/memoryEngine/" directory and 9 proc nodes. +* Write paramenters and request to these proc nodes and read the output from related proc node. +*/ + +#include "memoryEngine.h" + +/* +* proc entries +*/ +struct proc_dir_entry *dir = NULL; /// the directory of the MEMORY INJECT Moudle +struct proc_dir_entry *proc_pid = NULL; /// write only +struct proc_dir_entry *proc_va = NULL; /// write only +struct proc_dir_entry *proc_ctl = NULL; /// write only +struct proc_dir_entry *proc_kFuncName = NULL; /// write only +struct proc_dir_entry *proc_val = NULL; /// rw +struct proc_dir_entry *proc_signal = NULL; /// rw +struct proc_dir_entry *proc_pa = NULL; /// read only +struct proc_dir_entry *proc_taskINfo = NULL; /// read only + +/* +* proc node values +*/ +int pid; /// pid +unsigned long va; /// virtual Address +unsigned long pa; /// physical Addreess +int ctl; /// ctl +int signal; /// signal +char kFuncName[MAX_LINE]; /// kFuncName +long memVal; /// memVal + +unsigned long ack_pa; /// physical Address +unsigned long ack_va; /// virtual Address +int ack_signal; /// signal +int ret; /// return value +char taskInfo[PAGE_SIZE]; /// taskInfo + +/////////////////////////////////////////////// + +unsigned long userspace_phy_mem; /// user space physical memory +long orig_pa_data; /// origin data of the physics memory +long new_pa_data; /// the new data you want write to physics memory + +int faultInterval; + +/* +* kprobe +*/ +static struct kprobe kp_kFunc; + +struct jprobe jprobe1 = +{ + .entry = jforce_sig_info, + .kp = + { + .symbol_name = "force_sig_info", + }, +}; + +//时钟中断数计数 +static int count = 0; + +//保存原始代码 +static long orig_code = 0; + +/* +* process the request +*/ +void do_request(void) +{ + struct task_struct *task = NULL; + unsigned long pa = 0; + long kernel_va = 0; + int status; + + /// get a task's memory map information + if(ctl == REQUEST_TASK_INFO) + { + dbginfo("Rcv request:Get task info\n"); + + memset(taskInfo,'\0',sizeof(taskInfo)); + + if(pid <= 0) + { + ack_signal = ACK_TASK_INFO; + return; + } + task = findTaskByPid(pid); + + if( task != NULL ) + { + getTaskInfo(task, taskInfo, sizeof(taskInfo)); + } + ack_signal = ACK_TASK_INFO; + + return; + } + /// convert a process's linear address to physical address + else if(ctl == REQUEST_V2P) + { + task = findTaskByPid(pid); + if( task == NULL ) + { + dbginfo("No such process\n"); + ack_pa = -1; + ack_signal = ACK_V2P; + return; + } + if( task->mm == NULL ) + { + ack_pa = -1; + ack_signal = ACK_V2P; + return; + } + ack_pa = v2p(task->mm,va,&status); + if(ack_pa == FAIL) + { + dbginfo("No physical address\n"); + } + ack_signal = ACK_V2P; + return; + } + /// convert kernel virtual address to physical address + else if(ctl == REQUEST_KV2P) + { + ack_pa = kv2p(va,&status); + if(pa == FAIL) + { + dbginfo("No physical address\n"); + } + ack_signal = ACK_KV2P; + return; + } + /// get kernel function's addr(kernel virtual address) + else if(ctl == REQUEST_KFUNC_VA) + { + ack_va = kFunc2v(kFuncName); + ack_signal = ACK_KFUNC_VA; + return; + } + /// 请求读取内核函数起始地址内容 + else if(ctl == REQUEST_READ_KFUNC) + { + kernel_va = kFunc2v(kFuncName); + memVal = *((long *)kernel_va); + ack_signal = ACK_READ_KFUNC; + } + /// 请求改写内核函数起始地址内容 + else if(ctl == REQUEST_WRITE_KFUNC) + { + //利用kprobe,在第一次调用do_timer()时,注入故障 + int ret; + count = 0; + if(strlen(kFuncName) > 0) + { + faultInterval = 1; //故障仅持续一个时钟周期 + kp_kFunc.addr = 0; + kp_kFunc.symbol_name = kFuncName; + kp_kFunc.pre_handler = handler_pre_kFunc; + ret = register_kprobe(&kp_kFunc); + if(ret < 0) + { + dbginfo("Fained to register kprobe\n"); + ack_signal = ACK_WRITE_KFUNC; + return; + } + + //等待故障注入结束 + dbginfo("start count\n"); + int temp=0; + while(1) + { + if(count == -1) + { + unregister_kprobe(&kp_kFunc); + dbginfo("recovery\n"); + break; + } + if(temp == -1) + { + break; + } + temp++; + //dbginfo("count:%d\n",count); + } + } + ack_signal = ACK_WRITE_KFUNC; + dbginfo("Success to inject MTTR fault\n"); + return; + } + +} + +/* +* get a task's memory map information +*/ +int getTaskInfo(struct task_struct *pTask, char *pData, int length) +{ + struct mm_struct *pMM; + struct vm_area_struct *pVMA; + struct vm_area_struct *p; + char file[MAX_LINE]; + struct dentry *pPath = NULL; + char *end, *start; + char *info = pData; + + long phy_addr; + unsigned long start_va,end_va; + int status; + + if(pTask == NULL) { return FAIL; } + if((pMM = pTask->mm) == NULL) { return FAIL; } + + memset(pData, '\0', length); + //前19个字段是关于进程内存信息的总体信息 + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->total_vm, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->locked_vm, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->shared_vm, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->exec_vm, DELIMITER); + + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->stack_vm, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->reserved_vm, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->def_flags, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->nr_ptes, DELIMITER); + + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->start_code, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->end_code, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->start_data, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->end_data, DELIMITER); + + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->start_brk, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->brk, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->start_stack, DELIMITER); + + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->arg_start, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->arg_end, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->env_start, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->env_end, DELIMITER); + + pVMA = pMM->mmap; + if(pVMA == NULL) { return OK; } + for(p=pVMA; p!=NULL; p=p->vm_next) + { + //起始地址 + safe_sprintf(pData, length, info+strlen(info), "%lx %lx ", p->vm_start, p->vm_end); + //属性 + if(p->vm_flags & VM_READ) + { safe_sprintf(pData, length, info+strlen(info), "r"); } + else + { safe_sprintf(pData, length, info+strlen(info), "-"); } + + if(p->vm_flags & VM_WRITE) + { safe_sprintf(pData, length, info+strlen(info), "w"); } + else + { safe_sprintf(pData, length, info+strlen(info), "-"); } + + if(p->vm_flags & VM_EXEC) + { safe_sprintf(pData, length, info+strlen(info), "x"); } + else + { safe_sprintf(pData, length, info+strlen(info), "-"); } + + if(p->vm_flags & VM_SHARED) + { safe_sprintf(pData, length, info+strlen(info), "s"); } + else + { safe_sprintf(pData, length, info+strlen(info), "p"); } + + //对应文件名 + if(p->vm_file != NULL) + { + if(p->vm_file->f_dentry != NULL) + { + safe_sprintf(pData, length, info+strlen(info), " "); + memset(file,'\0',sizeof(file)); + for(pPath = p->vm_file->f_dentry; pPath != NULL; pPath = pPath->d_parent) + { + if(strcmp(pPath->d_name.name,"/") != 0) + { + strcpy(file + strlen(file), pPath->d_name.name); + strcpy(file + strlen(file), "/"); + continue; + } + break; + } + do + { + end = file + strlen(file) - 1; + for(start = end - 1; *start != '/' && start > file; start--); + if(*start == '/') {start++;} + *end = '\0'; + + safe_sprintf(pData, length, info+strlen(info), "/%s", start); + *start = '\0'; + } while(start > file); + } + } + safe_sprintf(pData, length, info+strlen(info), "%c", DELIMITER); + + //对应物理地址页 + start_va = p->vm_start; + end_va = p->vm_end; + while(end_va > start_va) + { + safe_sprintf(pData, length, info+strlen(info), "%lx-%lx\t", start_va, start_va + PAGE_SIZE); + phy_addr = v2p(pMM, start_va, &status); + if(phy_addr != FAIL) + { + safe_sprintf(pData, length, info+strlen(info), "va:0x%lx <--> pa:0x%lx", start_va, phy_addr); + } + start_va += PAGE_SIZE; + safe_sprintf(pData, length, info+strlen(info), "%c", DELIMITER); + } + + safe_sprintf(pData, length, info+strlen(info), "%c", DELIMITER); + } + return OK; +} + +/* +* +*/ +static int handler_pre_kFunc(struct kprobe *p, struct pt_regs *regs) +{ + unsigned long va; + va = (unsigned long)p->addr; + if(va <= 0) { return OK; } + + //第一次触发 + if(count == 0) + { + //读取前64字节,注入故障 + orig_code = *((long *)va); + //_inject_fault(va,memVal); + *((long *)va) = memVal; //故障 + return OK; + } + count ++; + //到达结束时间 + if(count == faultInterval + 1) + { + //恢复code + *((long *)va) = orig_code; + count = -1; + } + return OK; +} + +/* +* find_task_by_pid maybe not supported +* O(n) is fine :) +*/ +struct task_struct * findTaskByPid(pid_t pid) +{ + struct task_struct *task = NULL; + + // Traversing the process in the system to find the PID + // add by gatieme @2016-03-20 + for_each_process(task) + { + if(task->pid == pid) + { + return task; + } + } + return NULL; +} + +/* +* convert a process's linear address to physical address +*/ +long v2p(struct mm_struct *pMM,unsigned long va,int *pStatus) +{ + pte_t *pte = NULL; + unsigned long phyaddress = FAIL; + + pte = getPte(pMM, va); + if(pte != NULL) + { + phyaddress = (pte_val(*pte) & PAGE_MASK) | (va & ~PAGE_MASK); + } + return phyaddress; +} + +/* +* convert kernel virtual address to physical address +*/ +long kv2p(unsigned long va,int *pStatus) +{ + if(va < 0) + return FAIL; + if(__pa(va) >= 0) + return __pa(va); + return FAIL; +} + +/* +* get kernel function's addr(kernel virtual address) +* the kernel function should be looked up in the System.map +*/ +static struct kprobe kp; +long kFunc2v(char *funcName) +{ + int ret; + unsigned long va; + + kp.addr = 0; + kp.symbol_name = funcName; + ret = register_kprobe(&kp); + if(ret < 0) + { + dbginfo("Fained to register kprobe\n"); + return FAIL; + } + va = (unsigned long)kp.addr; + unregister_kprobe(&kp); + if(va == 0) + return FAIL; + return va; +} + + + +/* +* +*/ +struct vm_area_struct * getVMA(struct mm_struct *pMM,unsigned long va) +{ + struct vm_area_struct *p; + if(pMM == NULL) return NULL; + p = pMM->mmap; + if(p == NULL) return NULL; + + for(; p != NULL; p = p->vm_next) + { + if( va >= p->vm_start && va < p->vm_end ) + { + return p; + } + } + return NULL; +} + +/* +* +*/ +pte_t * getPte(struct mm_struct *pMM, unsigned long va) +{ + pgd_t *pgd = NULL; + pmd_t *pmd = NULL; + pud_t *pud = NULL; + pte_t *pte = NULL; + + ///get the pdg entry pointer + pgd = pgd_offset(pMM, va); + if(pgd_none(*pgd)) { return NULL; } + + pud = pud_offset(pgd,va); + if(pud_none(*pud)) { return NULL; } + + pmd = pmd_offset(pud,va); + if(pmd_none(*pmd)) { return NULL; } + + pte = pte_offset_kernel(pmd,va); + if(pte_none(*pte)) { return NULL; } + if(!pte_present(*pte)) { return NULL; } + return pte; +} + +/* +* +*/ +int setVMAFlags(struct mm_struct *pMM,unsigned long va,int *pStatus,int flags) +{ + struct vm_area_struct *p; + p = getVMA(pMM,va); + if(p == NULL) return FAIL; + + if(flags > 0) + { + p->vm_flags |= VM_WRITE; + p->vm_flags |= VM_SHARED; + } + if(flags == 0) + { + p->vm_flags &= ~VM_WRITE; + p->vm_flags &= ~VM_SHARED; + } + else { return FAIL; } + return OK; +} + +/* +* +*/ +int setPageFlags(struct mm_struct *pMM,unsigned long va,int *pStatus,int flags) +{ + pte_t *pte = NULL; + pte_t ret; + pte = getPte(pMM, va); + if( pte == NULL ) { return FAIL; } + if(flags > 0) + { + ret = pte_mkwrite(*pte); + } + else if(flags == 0) + { + ret = pte_wrprotect(*pte); + } + else { return FAIL; } + return OK; +} + +/* +* +*/ +int proc_write_pid( struct file *file, + const char __user *buffer, + unsigned long count, + void * data) +{ + int iRet; + char sPid[MAX_LINE]; + + if(count <= 0) + { + return FAIL; + } + + memset(sPid, '\0', sizeof(sPid)); + ///////////////////////////////////////////////////////////////////// + // + // copy_from_user函数的目的是从用户空间拷贝数据到内核空间, + // 失败返回没有被拷贝的字节数,成功返回0. + // 这么简单的一个函数却含盖了许多关于内核方面的知识, + // 比如内核关于异常出错的处理. + // 从用户空间拷贝数据到内核中时必须很小心, + // 假如用户空间的数据地址是个非法的地址,或是超出用户空间的范围, + // 或是那些地址还没有被映射到,都可能对内核产生很大的影响, + // 如oops,或被造成系统安全的影响. + // 所以copy_from_user函数的功能就不只是从用户空间拷贝数据那样简单了, + // 他还要做一些指针检查连同处理这些问题的方法. + // + // 函数原型在[arch/i386/lib/usercopy.c]中 + // unsigned long + // copy_from_user( void *to, + // const void __user *from, + // unsigned long n) + // + ///////////////////////////////////////////////////////////////////// + // + // 将用户空间中, 地址buffr指向的count个数据拷贝到内核空间地址sPid中 + iRet = copy_from_user(sPid, buffer, count); + if(iRet != 0) + { + dbginfo("Error when copy_from_user...\n"); + return FAIL; + } + + iRet = sscanf(sPid, "%d", &pid); // 将读出来的数据sPid赋值给模块的全局变量pid + if(iRet != 1) + { + return FAIL; + } + dbginfo("Rcv pid:%d\n",pid); + + return count; +} + +/* +* +*/ +int proc_read_virtualAddr( char * page, + char **start, + off_t off, + int count, + int * eof, + void * data) +{ + int iLen; + + iLen = sprintf(page, "%lx", ack_va); + + + return iLen; +} + +/* +* +*/ +int proc_write_virtualAddr( struct file *file, + const char *buffer, + unsigned long count, + void * data) +{ + int iRet; + char sVa[MAX_LINE]; + + if(count <= 0) + { + return FAIL; + } + + memset(sVa, '\0', sizeof(sVa)); + + iRet = copy_from_user(sVa, buffer, count); + if(iRet) + { + return FAIL; + } + + iRet = sscanf(sVa,"%lx",&va); + if(iRet != 1) + { + return FAIL; + } + + dbginfo("Rcv virtual addr:0x%lx\n",va); + + return count; +} + +/* +* +*/ +int proc_write_ctl( struct file *file, + const char *buffer, + unsigned long count, + void * data) +{ + int iRet; + char sCtl[MAX_LINE]; + + if(count <= 0) + { + return FAIL; + } + + memset(sCtl, '\0', sizeof(sCtl)); + + iRet = copy_from_user(sCtl, buffer, count); + if(iRet) + { + return FAIL; + } + + iRet = sscanf(sCtl,"%d",&ctl); + if(iRet != 1) + { + return FAIL; + } + + do_request(); + + return count; +} + +/* +* +*/ +int proc_read_signal( char * page, + char **start, + off_t off, + int count, + int * eof, + void * data) +{ + int iLen; + iLen = sprintf(page, "%d", ack_signal); + return iLen; +} + +/* +* +*/ +int proc_write_signal( struct file *file, + const char *buffer, + unsigned long count, + void * data) +{ + int iRet; + char sSignal[MAX_LINE]; + + if(count <= 0) + { + return FAIL; + } + + memset(sSignal, '\0', sizeof(sSignal)); + iRet = copy_from_user(sSignal, buffer, count); + if(iRet) + { + return FAIL; + } + + iRet = sscanf(sSignal,"%d",&signal); + if(iRet != 1) + { + return FAIL; + } + + dbginfo("Rcv signal:%d\n",signal); + + return count; +} + +/* +* +*/ +int proc_read_pa(char * page,char **start, off_t off, int count, int * eof,void * data) +{ + int iLen; + iLen = sprintf(page, "%lx", ack_pa); + return iLen; +} + +/* +* +*/ +int proc_write_pa(struct file *file,const char *buffer,unsigned long count,void * data) +{ + int iRet; + char sPa[MAX_LINE]; + + if(count <= 0) { return FAIL; } + memset(sPa, '\0', sizeof(sPa)); + iRet = copy_from_user(sPa, buffer, count); + if(iRet) { return FAIL; } + iRet = sscanf(sPa,"%lx",&pa); + if(iRet != 1) { return FAIL; } + dbginfo("Rcv pa:0x%lx\n",pa); + return count; +} + +/* +* +*/ +int proc_write_kFuncName(struct file *file,const char *buffer,unsigned long count,void * data) +{ + int iRet; + if(count <= 0) { return FAIL; } + memset(kFuncName, '\0', sizeof(kFuncName)); + iRet = copy_from_user(kFuncName, buffer, count); + if(iRet) { return FAIL; } + //remove '\n' + if(kFuncName[strlen(kFuncName) - 1] == '\n') + { + kFuncName[strlen(kFuncName) - 1] = '\0'; + } + dbginfo("Rcv kernel func name:%s\n",kFuncName); + return count; +} + +/* +* +*/ +int proc_read_taskInfo(char * page,char **start, off_t off, int count, int * eof,void * data) +{ + int iLen; + iLen = sprintf(page, "%s", taskInfo); + return iLen; +} + +/* +* +*/ +int proc_write_memVal(struct file *file,const char *buffer,unsigned long count,void * data) +{ + int iRet; + char sMemVal[MAX_LINE]; + + if(count <= 0) + { + return FAIL; + } + + memset(sMemVal, '\0', sizeof(sMemVal)); + iRet = copy_from_user(sMemVal, buffer, count); + if(iRet) + { + return FAIL; + } + + iRet = sscanf(sMemVal,"%lx",&memVal); + if(iRet != 1) + { + return FAIL; + } + + dbginfo("Rcv memVal:0x%lx\n",memVal); + return count; +} + +/* +* +*/ +int proc_read_memVal( char * page, + char **start, + off_t off, + int count, + int * eof, + void * data) +{ + int iLen; + iLen = sprintf(page, "%lx", memVal); + return iLen; +} + +/* +* init memory fault injection module +* 初始化内存注入故障模块 +* +* 使用proc_mkdir()创建一个dir = /proc/memoryEngine +* 再利用create_proc_read_entry()函数创建一个processinfo文件。 +* 我们从模块里面获取的信息都将写入到这些文件中。 +* +*/ +static int __init initME(void) +{ + /* + * create a direntory named "memoryEngine" in /proc for the moudles + * as the interface between the kernel and the user program. + * + */ + dir = proc_mkdir("memoryEngine", NULL); + if(dir == NULL) + { + dbginfo("Can't create /proc/memoryEngine/\n"); + return FAIL; + } + dir->owner = THIS_MODULE; + + /// create a file named "pid" in direntory + proc_pid = create_proc_entry("pid", PERMISSION, dir); + if(proc_pid == NULL) + { + dbginfo("Can't create /proc/memoryEngine/pid\n"); + + remove_proc_entry("memoryEngine", NULL); + + return FAIL; + } + proc_pid->write_proc = proc_write_pid; /// write only + proc_pid->owner = THIS_MODULE; + + + /// create a file named "virtualAddr" in direntory + proc_va = create_proc_entry("virtualAddr", PERMISSION, dir); + if(proc_va == NULL) + { + dbginfo("Can't create /proc/memoryEngine/virtualAddr\n"); + + remove_proc_entry("pid", dir); + remove_proc_entry("memoryEngine", NULL); + + return FAIL; + } + proc_va->read_proc = proc_read_virtualAddr; // can read + proc_va->write_proc = proc_write_virtualAddr; // can write + proc_va->owner = THIS_MODULE; + + /// create a file named "ctl" in direntory + proc_ctl = create_proc_entry("ctl", PERMISSION, dir); + if(proc_ctl == NULL) + { + dbginfo("Can't create /proc/memoryEngine/ctl\n"); + + remove_proc_entry("pid", dir); + remove_proc_entry("virtualAddr", dir); + remove_proc_entry("memoryEngine", NULL); + + return FAIL; + } + proc_ctl->write_proc = proc_write_ctl; // write only + proc_ctl->owner = THIS_MODULE; + + /// create a file named "signal" in direntory + proc_signal = create_proc_entry("signal", PERMISSION, dir); + if(proc_signal == NULL) + { + dbginfo("Can't create /proc/memoryEngine/signal\n"); + + remove_proc_entry("pid", dir); + remove_proc_entry("virtualAddr", dir); + remove_proc_entry("ctl", dir); + remove_proc_entry("memoryEngine", NULL); + + return FAIL; + } + proc_signal->read_proc = proc_read_signal; // can read + proc_signal->write_proc = proc_write_signal; // can write + proc_signal->owner = THIS_MODULE; + + /// create a file named "physicalAddr" in direntory + proc_pa = create_proc_entry("physicalAddr", PERMISSION, dir); + if(proc_pa == NULL) + { + dbginfo("Can't create /proc/memoryEngine/physicalAddr\n"); + + remove_proc_entry("pid", dir); + remove_proc_entry("virtualAddr", dir); + remove_proc_entry("ctl", dir); + remove_proc_entry("memoryEngine", NULL); + + return FAIL; + } + + proc_pa->read_proc = proc_read_pa; // can read + proc_pa->write_proc = proc_write_pa; // can write + + + /// create a file named "kFuncName" in direntory + proc_kFuncName = create_proc_entry("kFuncName", PERMISSION, dir); + if(proc_kFuncName == NULL) + { + dbginfo("Can't create /proc/memoryEngine/kFuncName\n"); + + remove_proc_entry("pid", dir); + remove_proc_entry("virtualAddr", dir); + remove_proc_entry("ctl", dir); + remove_proc_entry("physicalAddr", dir); + remove_proc_entry("memoryEngine", NULL); + + return FAIL; + } + proc_kFuncName->write_proc = proc_write_kFuncName; // write only + + + /// create a file named "taskInfo" in direntory + proc_taskINfo = create_proc_entry("taskInfo", PERMISSION, dir); + if(proc_taskINfo == NULL) + { + dbginfo("Can't create /proc/memoryEngine/taskInfo\n"); + + remove_proc_entry("pid", dir); + remove_proc_entry("virtualAddr", dir); + remove_proc_entry("ctl", dir); + remove_proc_entry("physicalAddr", dir); + remove_proc_entry("kFuncName", dir); + remove_proc_entry("memoryEngine", NULL); + + return FAIL; + } + proc_taskINfo->read_proc = proc_read_taskInfo; // read only + + /// create a file named "memVal" in direntory + proc_val = create_proc_entry("memVal", PERMISSION, dir); + if(proc_val == NULL) + { + dbginfo("Can't create /proc/memoryEngine/memVal\n"); + + remove_proc_entry("pid", dir); + remove_proc_entry("virtualAddr", dir); + remove_proc_entry("ctl", dir); + remove_proc_entry("physicalAddr", dir); + remove_proc_entry("kFuncName", dir); + remove_proc_entry("taskInfo", dir); + remove_proc_entry("memoryEngine", NULL); + + return FAIL; + } + proc_val->write_proc = proc_write_memVal; // can write + proc_val->read_proc = proc_read_memVal; // can read + + + ret = register_jprobe(&jprobe1); + if (ret < 0) + { + printk("register_jprobe jprobe1 failed, returned %d\n", ret); + return ret; + } + printk("Planted jprobe at force_sig_info: %p\n", jprobe1.kp.addr); + + dbginfo("Memory engine module init\n"); + return OK; +} + + +static int jforce_sig_info(int sig,struct siginfo *info,struct task_struct *t) +{ + printk("MemSysFI: kernel is sending signal %d to process pid: %d, comm: %s\n",sig,t->pid,t->comm); +/* + if (f_inject == 'N') + { + jprobe_return(); + return 0; + } + + down_interruptible(&sem); + if ( addone(addone(inj_info.rear))==inj_info.front ) + { + */ + /*error:队列满*/ + /* + sprintf(inj_info.inj_log[inj_info.rear].msg,"caution : buf is full, messages have been dropped\n"); + } + else + { + inj_info.rear = addone(inj_info.rear); + sprintf(inj_info.inj_log[inj_info.rear].msg,"warning : kernel is sending signal %d to process pid: %d, comm: %s\n",sig,current->pid,current->comm); + //inj_info->inj_log[inj_info->rear ] = x ; + } + up(&sem); + */ + /* + if(message!=NULL) + { + for(i=0;i<256;i++) + message[i]='\0'; + + sprintf(message,"warning : kernel is sending signal %d to process pid: %d, comm: %s\n\0",sig,current->pid,current->comm); + } + else + return -1; + + + struct bufferList *buflist; + buflist = (struct bufferList *)kmalloc(sizeof(struct bufferList),GFP_KERNEL); + buflist->pNext = NULL; + buflist->buffer = message; + + down_interruptible(&sem); + if(Head==NULL) + { + Head = buflist; + Tail = Head; + } + else + { + Tail->pNext = buflist; + Tail = buflist; + } + flag = 1; + up(&sem); + */ + +// wake_up_interruptible(&wq2); + + jprobe_return(); + return 0; +} + +/* +* uninit memory fault injection module +*/ +static void __exit exitME(void) +{ + remove_proc_entry("pid", dir); + remove_proc_entry("virtualAddr", dir); + remove_proc_entry("ctl", dir); + remove_proc_entry("signal", dir); + remove_proc_entry("physicalAddr", dir); + remove_proc_entry("kFuncName", dir); + remove_proc_entry("taskInfo", dir); + remove_proc_entry("memVal", dir); + remove_proc_entry("memoryEngine", NULL); + unregister_jprobe(&jprobe1); + printk("jprobe at %p unregistered.\n", jprobe1.kp.addr); + dbginfo("Memory engine module exit\n"); +} + +module_init(initME); +module_exit(exitME); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("HIT CS HDMC team"); +MODULE_DESCRIPTION("Memory Engine Module."); + diff --git a/study/engine/arm64/memoryEngine.h b/study/engine/arm64/memoryEngine.h new file mode 100644 index 0000000..f13d074 --- /dev/null +++ b/study/engine/arm64/memoryEngine.h @@ -0,0 +1,126 @@ +/* +* Author: HIT CS HDMC team. +* Create: 2010-3-12 8:20:01 +* Last modified: 2010-6-13 14:13:47 +*/ + +#ifndef _MEMORY_ENGINE_H +#define _MEMORY_ENGINE_H + +/* +* common include header files +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_LINE 256 /// max length of a line +#define DELIMITER '\n' /// the char is used to split the taskinfo +#define PERMISSION 0644 /// proc node permission +/* +* return values +*/ +#define OK 0 +#define FAIL -1 +#define PGD_NONE -2 +#define PUD_NONE -3 +#define PMD_NONE -4 +#define PTE_NONE -5 +#define PTE_NOT_PRESENT -6 + + + +/* +* request command +*/ +#define REQUEST_TASK_INFO 1 /// get a task's memory map information +#define REQUEST_V2P 2 /// convert a process's linear address to physical address +#define REQUEST_KV2P 3 /// convert kernel virtual address to physical address +#define REQUEST_KFUNC_VA 4 /// get kernel function's addr(kernel virtual address) +#define REQUEST_READ_KFUNC 5 /// 璇锋眰璇诲彇鍐呮牳鍑芥暟璧峰鍦板潃鍐呭 +#define REQUEST_WRITE_KFUNC 6 /// 璇锋眰鏀瑰啓鍐呮牳鍑芥暟璧峰鍦板潃鍐呭 +///#define REQUEST_WRITE 10 /// 璇锋眰鏀瑰啓鎸囧畾鐗╃悊鍦板潃鍐呭锛屾敼涓虹敤鎴锋佸疄鐜版鍔熻兘 +///#define REQUEST_MEM 11 /// 璇锋眰鑾峰彇鍏ㄩ儴鐗╃悊鍐呭瓨淇℃伅 +///#define REQUEST_ADDR_STOP 12 /// + +/* +* ack signals +*/ +#define ACK_TASK_INFO REQUEST_TASK_INFO +#define ACK_V2P REQUEST_V2P +#define ACK_KV2P REQUEST_KV2P +#define ACK_KFUNC_VA REQUEST_KFUNC_VA +#define ACK_READ_KFUNC REQUEST_READ_KFUNC +#define ACK_WRITE_KFUNC REQUEST_WRITE_KFUNC +///#define REQUEST_WRITE REQUEST_WRITE +///#define ACK_MEM REQUEST_MEM +///#define ACK_ADDR_STOP REQUEST_ADDR_STOP + +/* +* #define DEBUG ,dbginfo() will add more debug information into nomal printk. +* #define SILENCE ,dbginfo() will print nothing. +* Otherwise ,dbginfo() equals to printk. +*/ +#ifdef __FUNCTION__ +#ifdef __LINE__ + #ifdef DEBUG + //printk with line and function name + #define dbginfo(format,args...); \ + printk(KERN_INFO "%s-L%d:"format,__FUNCTION__,__LINE__,##args); + #elif defined SILENCE + #define dbginfo(format,args...); + #else //printk normally + #define dbginfo(format,args...); printk(KERN_INFO format,##args); + #endif +#endif +#endif + +/* +* safe sprintf +* It will not be out of range. +*/ +#define safe_sprintf(start, n, p, format, args...); \ + { if( (p - start) < n ) { snprintf( (char *)p, (n - (p - start)), format, ##args ); } } + + +/* +* utility functions +*/ +static int handler_pre_kFunc(struct kprobe *p, struct pt_regs *regs); +struct task_struct *findTaskByPid(pid_t pid); +long v2p(struct mm_struct *pMM,unsigned long va,int *pStatus); +long kv2p(unsigned long va,int *pStatus); +long kFunc2v(char *funcName); +struct vm_area_struct * getVMA(struct mm_struct *pMM,unsigned long va); +pte_t * getPte(struct mm_struct *pMM,unsigned long va); +int setVMAFlags(struct mm_struct *pMM,unsigned long va,int *pStatus,int flags); +int setPageFlags(struct mm_struct *pMM,unsigned long va,int *pStatus,int flags); +int getTaskInfo(struct task_struct *pTask, char *pData, int length); + +/* +* proc entry function +*/ +int proc_write_pid(struct file *file,const char __user *buffer,unsigned long count,void * data); +int proc_read_virtualAddr(char * page,char **start, off_t off, int count, int * eof,void * data); +int proc_write_virtualAddr(struct file *file,const char *buffer,unsigned long count,void * data); +int proc_write_ctl(struct file *file,const char *buffer,unsigned long count,void * data); +int proc_read_signal(char * page,char **start, off_t off, int count, int * eof,void * data); +int proc_write_signal(struct file *file,const char *buffer,unsigned long count,void * data); +int proc_read_pa(char * page,char **start, off_t off, int count, int * eof,void * data); +static int jforce_sig_info(int sig,struct siginfo *info,struct task_struct *t); +#endif + diff --git a/study/engine/common.h b/study/engine/common.h new file mode 100644 index 0000000..56854cf --- /dev/null +++ b/study/engine/common.h @@ -0,0 +1,230 @@ +/* +* Author: HIT CS HDMC team. +* Last modified by zhaozhilong: 2010-1-14 +*/ +#ifndef _COMMON_H_ +#define _COMMON_H_ + + + + + +/// 褰撳墠瀛楃鏄暟瀛 +#define IsDigit(c) (c >= '0' && c <= '9') + +/// 褰撳墠瀛楃鏄8杩涘埗鏁版嵁 +#define IsOctDigit(c) (c >= '0' && c <= '7') + +/// 褰撳墠瀛楃鏄16杩涘埗鏁版嵁 +#define IsHexDigit(c) (IsDigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) + +/// 褰撳墠瀛楃鏄瓧姣嶆垨鑰卂 +#define IsLetter(c) ((c >= 'a' && c <= 'z') || (c == '_') || (c >= 'A' && c <= 'Z')) + +/// 褰撳墠鑷礋鏄惁婊¤冻C鐨勫彉閲忓懡鍚嶈鍒 +#define IsLetterOrDigit(c) (IsLetter(c) || IsDigit(c)) +#define IsIdentifier IsLetterOrDigit + +/// 褰撳墠瀛楃鏄┖鐧藉瓧绗 +#define IsSpace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r') + + + +/// 鍙栧嚭褰撳墠淇℃伅鐨勯珮4浣 +#define HIGH_4BIT(v) ((v) >> (8 * sizeof(int) - 4) & 0x0f) +/// 鍙栧嚭褰撳墠淇℃伅鐨勯珮3浣 +#define HIGH_3BIT(v) ((v) >> (8 * sizeof(int) - 3) & 0x07) +/// 鍙栧嚭褰撳墠淇℃伅鐨勯珮1浣 +#define HIGH_1BIT(v) ((v) >> (8 * sizeof(int) - 1) & 0x01) +//#define ALIGN(size, align) ((size + align - 1) & (~(align - 1))) + +#define BitGet(number, pos) ((number) >> (pos) & 1) /// 鐢ㄥ畯寰楀埌鏌愭暟鐨勬煇浣 +#define BitSet(number, pos) ((number) |= 1 << (pos)) /// 鎶婃煇浣嶇疆1 +#define BitClr(number, pos) ((number) &= ~(1 << (pos))) /// 鎶婃煇浣嶆竻0 +#define BitCpl(number, pos) ((number) ^= 1 << (pos)) /// 鎶妌umber鐨凱OS浣嶅彇鍙 + + +///03: 寰楀埌鎸囧畾鍦板潃涓婄殑涓涓瓧鑺傛垨瀛 +#define MEM_B(x) (*((byte *)(x))) +#define MEM_W(x) (*((word *)(x))) + +///04: 姹傛渶澶у煎拰鏈灏忓 +#define MAX(x,y) (((x)>(y)) ? (x) : (y)) +#define MIN(x,y) (((x) < (y)) ? (x) : (y)) + +///05: 寰楀埌涓涓猣ield鍦ㄧ粨鏋勪綋(struct)涓殑鍋忕Щ閲 +#define FPOS(type,field) ((dword)&((type *)0)->field) + +///06: 寰楀埌涓涓粨鏋勪綋涓璮ield鎵鍗犵敤鐨勫瓧鑺傛暟 +#define FSIZ(type,field) sizeof(((type *)0)->field) + +///07: 鎸夌収LSB鏍煎紡鎶婁袱涓瓧鑺傝浆鍖栦负涓涓猈ord +#define FLIPW(ray) ((((word)(ray)[0]) * 256) + (ray)[1]) + +///08: 鎸夌収LSB鏍煎紡鎶婁竴涓猈ord杞寲涓轰袱涓瓧鑺 +#define FLOPW(ray,val) (ray)[0] = ((val)/256); (ray)[1] = ((val) & 0xFF) + +///09: 寰楀埌涓涓彉閲忕殑鍦板潃锛坵ord瀹藉害锛 +#define B_PTR(var) ((byte *) (void *) &(var)) +#define W_PTR(var) ((word *) (void *) &(var)) + +///10: 寰楀埌涓涓瓧鐨勯珮浣嶅拰浣庝綅瀛楄妭 +#define WORD_LO(xxx) ((byte) ((word)(xxx) & 255)) +#define WORD_HI(xxx) ((byte) ((word)(xxx) >> 8)) + +///11: 杩斿洖涓涓瘮X澶х殑鏈鎺ヨ繎鐨8鐨勫嶆暟 +#define RND8(x) ((((x) + 7)/8) * 8) + +///12: 灏嗕竴涓瓧姣嶈浆鎹负澶у啓 +#define UPCASE(c) (((c)>='a' && (c) <= 'z') ? ((c) - 0x20) : (c)) +#define ToUpper(c) (c & ~0x20) + +///13: 鍒ゆ柇瀛楃鏄笉鏄10杩涘肩殑鏁板瓧 +#define DECCHK(c) ((c)>='0' && (c)<='9') + +///14: 鍒ゆ柇瀛楃鏄笉鏄16杩涘肩殑鏁板瓧 +#define HEXCHK(c) (((c) >= '0' && (c)<='9') ((c)>='A' && (c)<= 'F') \ +((c)>='a' && (c)<='f')) + +///15: 闃叉婧㈠嚭鐨勪竴涓柟娉 +#define INC_SAT(val) (val=((val)+1>(val)) ? (val)+1 : (val)) + +///16: 杩斿洖鏁扮粍鍏冪礌鐨勪釜鏁 +#define ARR_SIZE(a) (sizeof((a))/sizeof((a[0]))) + +///17: 杩斿洖涓涓棤绗﹀彿鏁皀灏剧殑鍊糓OD_BY_POWER_OF_TWO(X,n)=X%(2^n) +#define MOD_BY_POWER_OF_TWO( val, mod_by ) ((dword)(val) & (dword)((mod_by)-1)) + +///18: 瀵逛簬IO绌洪棿鏄犲皠鍦ㄥ瓨鍌ㄧ┖闂寸殑缁撴瀯,杈撳叆杈撳嚭澶勭悊 +#define inp(port) (*((volatile byte *)(port))) +#define inpw(port) (*((volatile word *)(port))) +#define inpdw(port) (*((volatile dword *)(port))) +#define outp(port,val) (*((volatile byte *)(port))=((byte)(val))) +#define outpw(port, val) (*((volatile word *)(port))=((word)(val))) +#define outpdw(port, val) (*((volatile dword *)(port))=((dword)(val))) + + + +#define DEBUG + +/** + * Macros to help with debugging. Set SCULL_DEBUG to 1 enable + * debugging (which you can do from the Makefile); these macros work + * in both kernelspace and userspace. + */ + +/* undef it, just in case someone else defined it. */ + +#ifdef dbgprint +#undef dbgprint +#endif // dbgprint + +#ifdef dprint +#undef dprint +#endif // dprint + +#ifdef dout +#undef dount +#endif // dout + + +/**when you define DEBUG macro + dbgprint to use printk with line and funcitonname in kernel + dprint to use print without line and funcitonname in kernel + + + dbgprint to use printf with line and funcitonname in userspace + dprint to use printf without line and funcitonname in userspace + it's the same to dbgcout and dcout in userspace + +*/ +#ifdef DEBUG + + #ifdef __KERNEL__ + #ifdef __FILE__ + #ifdef __LINE__ + //printk with line and function name + #define dbgprint(format, args...) \ + printk(KERN_INFO "[%s, %d] : "format, __FILE__, __LINE__, ##args) + #endif // __FILE__ && __LINE__ + #endif // __FILE__ && __LINE__ + + //printk without line and function name + #define dprint(format,args...) printk(KERN_INFO format, ##args) + #define dprintk(format,args...) printk(KERN_INFO format, ##args) + + + #else // userspace + + #ifdef __FILE__ + #ifdef __LINE__ + //printf with line and function name + #define dbgprint(format, args...) \ + printf("[%s,%d] : "format, __FILE__, __LINE__, ##args) + #define dbgcout std::cout <<"[" <<__FILE__ <<", " <<__LINE__ <<"] : " + + #endif // __FILE__ && __LINE__ + #endif // __FILE__ && __LINE__ + + /* Debugging is on and we are in userspace. */ + #define dprint(format, args...) printf(format, ## args) + #define dprintf(format, args...) printf(format, ## args) + #define dcout cout + + + #endif // __KERNEL__ + +#else /* Not debugging: do nothing. */ + #define dbgprint(format,args...) + + #define dprint(format, args...) + #define dprintf(format, args...) + #define dcout 0 && cout +#endif + +/* PDEBUGG is a placeholder that makes it easy to "comment out" the debugging + statements without deleting them. */ +#undef undprint +#define undprint(format, args...) + +#undef undcout +#define undcout 0 && count + +#undef undbgprint +#define undprint(format, args...) + +#undef undbgcout +#define undbgcout 0 && cout + + + +/* +* #define DEBUG ,dbginfo() will add more debug information into nomal printk. +* #define SILENCE ,dbginfo() will print nothing. +* Otherwise ,dbginfo() equals to printk. +*/ + + +#ifdef __FUNCTION__ +#ifdef __LINE__ + #ifdef DEBUG + //printk with line and function name + #define dbginfo(format,args...); \ + printk(KERN_INFO"MemFI-[%s, %d] : "format, __FUNCTION__, __LINE__, ##args); + #elif defined SILENCE + #define dbginfo(format,args...); + #else //printk normally + #define dbginfo(format,args...); printk(KERN_INFO format, ##args); + #endif +#endif +#endif + +/* +* safe sprintf +* It will not be out of range. +*/ +#define safe_sprintf(start, n, p, format, args...); \ + { if( (p - start) < n ) { snprintf( (char *)p, (n - (p - start)), format, ##args ); } } + + +#endif /* _COMMON_H_ */ diff --git a/study/engine/mem/Makefile b/study/engine/mem/Makefile new file mode 100644 index 0000000..361996d --- /dev/null +++ b/study/engine/mem/Makefile @@ -0,0 +1,21 @@ +# Makefile for the memory fault injection engine. +# +# Author: HIT CS HDMC team. +# Create: 2010-3-12 8:46 +# Last modified: 2010-6-13 13:55:29 +# Description: +# This program is loaded as a kernel(v2.6.18 or later) module. +# Use "make install" to load it into kernel. +# Use "make remove" to remove the module out of kernel. +# + +obj-m := mem.o +all: + make -C /lib/modules/`uname -r`/build M=`pwd` modules +install: + insmod memoryEngine.ko +remove: + rmmod memoryEngine +clean: + make -C /lib/modules/`uname -r`/build M=`pwd` clean + rm -f modules.order Module.symvers Module.markers diff --git a/study/engine/mem/mem.c b/study/engine/mem/mem.c new file mode 100644 index 0000000..d0d0f4b --- /dev/null +++ b/study/engine/mem/mem.c @@ -0,0 +1,125 @@ +/***************************************************************** +鏂囦欢鍚嶏細mem.c +杈撳叆鍙傛暟锛 +pid 鎺ユ敹寰呮煡璇㈣繘绋嬬殑PID +va 鎺ユ敹寰呮煡璇㈢殑铏氭嫙鍦板潃 +*****************************************************************/ +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); + +static int pid; +static unsigned long va; + +module_param(pid, int, 0644); +module_param(va, ulong, 0644); + +static int find_pgd_init(void) +{ + unsigned long pa = 0; + struct task_struct *pcb_tmp = NULL; + pgd_t *pgd_tmp = NULL; + pud_t *pud_tmp = NULL; + pmd_t *pmd_tmp = NULL; + pte_t *pte_tmp = NULL; + + printk(KERN_INFO"PAGE_OFFSET = 0x%lx\n", PAGE_OFFSET); + printk(KERN_INFO"PGDIR_SHIFT = %d\n", PGDIR_SHIFT); + printk(KERN_INFO"PUD_SHIFT = %d\n", PUD_SHIFT); + printk(KERN_INFO"PMD_SHIFT = %d\n", PMD_SHIFT); + printk(KERN_INFO"PAGE_SHIFT = %d\n", PAGE_SHIFT); + + printk(KERN_INFO"PTRS_PER_PGD = %d\n", PTRS_PER_PGD); + printk(KERN_INFO"PTRS_PER_PUD = %d\n", PTRS_PER_PUD); + printk(KERN_INFO"PTRS_PER_PMD = %d\n", PTRS_PER_PMD); + printk(KERN_INFO"PTRS_PER_PTE = %d\n", PTRS_PER_PTE); + + printk(KERN_INFO"PAGE_MASK = 0x%lx\n", PAGE_MASK); + + //if(!(pcb_tmp = find_task_by_vpid(pid))) linux-3.0 + if(!(pcb_tmp = find_task_by_pid(pid))) // linux-2.6 + { + printk(KERN_INFO"Can't find the task %d .\n", pid); + + return 0; + } + printk(KERN_INFO"pgd = 0x%p\n", pcb_tmp->mm->pgd); + + /* 鍒ゆ柇缁欏嚭鐨勫湴鍧va鏄惁鍚堟硶(va<vm_end)*/ + if(!find_vma(pcb_tmp->mm, va)) + { + printk(KERN_INFO"virt_addr 0x%lx not available.\n", va); + + return 0; + } + + pgd_tmp = pgd_offset(pcb_tmp->mm, va); + printk(KERN_INFO"pgd_tmp = 0x%p\n", pgd_tmp); + printk(KERN_INFO"pgd_val(*pgd_tmp) = 0x%lx\n", pgd_val(*pgd_tmp)); + if(pgd_none(*pgd_tmp)) + { + printk(KERN_INFO"Not mapped in pgd.\n"); + + return 0; + } + + pud_tmp = pud_offset(pgd_tmp, va); + printk(KERN_INFO"pud_tmp = 0x%p\n", pud_tmp); + printk(KERN_INFO"pud_val(*pud_tmp) = 0x%lx\n", pud_val(*pud_tmp)); + + if(pud_none(*pud_tmp)) + { + printk(KERN_INFO"Not mapped in pud.\n"); + + return 0; + } + + pmd_tmp = pmd_offset(pud_tmp, va); + printk(KERN_INFO"pmd_tmp = 0x%p\n", pmd_tmp); + printk(KERN_INFO"pmd_val(*pmd_tmp) = 0x%lx\n", pmd_val(*pmd_tmp)); + if(pmd_none(*pmd_tmp)) + { + printk(KERN_INFO"Not mapped in pmd.\n"); + return 0; + } + + /*鍦ㄨ繖閲岋紝鎶婂師鏉ョ殑pte_offset_map()鏀规垚浜唒te_offset_kernel*/ + pte_tmp = pte_offset_kernel(pmd_tmp, va); + + printk(KERN_INFO"pte_tmp = 0x%p\n", pte_tmp); + printk(KERN_INFO"pte_val(*pte_tmp) = 0x%lx\n", pte_val(*pte_tmp)); + + if(pte_none(*pte_tmp)) + { + printk(KERN_INFO"Not mapped in pte.\n"); + return 0; + } + if(!pte_present(*pte_tmp)) + { + printk(KERN_INFO"pte not in RAM.\n"); + return 0; + } + + pa = (pte_val(*pte_tmp) & PAGE_MASK) | (va & ~PAGE_MASK); + printk(KERN_INFO"virt_addr 0x%lx in RAM is 0x%lx .\n", va, pa); + printk(KERN_INFO"contect in 0x%lx is 0x%lx\n", pa, *(unsigned long *)((char *)pa + PAGE_OFFSET)); + + return 0; + +} + +static void find_pgd_exit(void) +{ + printk(KERN_INFO"Goodbye!\n"); +} + +module_init(find_pgd_init); +module_exit(find_pgd_exit); + + diff --git a/study/engine/mem/v2p.c b/study/engine/mem/v2p.c new file mode 100644 index 0000000..01f351c --- /dev/null +++ b/study/engine/mem/v2p.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include +#include +#include + +#define page_map_file "/proc/self/pagemap" +#define PFN_MASK ((((uint64_t)1)<<55)-1) +#define PFN_PRESENT_FLAG (((uint64_t)1)<<63) + + +int mem_addr_vir2phy(unsigned long vir, unsigned long *phy) +{ + int fd; + int page_size = getpagesize(); + unsigned long vir_page_idx = vir / page_size; + unsigned long pfn_item_offset = vir_page_idx * sizeof(uint64_t); + uint64_t pfn_item; + + fd = open(page_map_file, O_RDONLY); + if (fd < 0) + { + printf("open %s failed", page_map_file); + + return -1; + } + + + if ((off_t)-1 == lseek(fd, pfn_item_offset, SEEK_SET)) + { + printf("lseek %s failed", page_map_file); + + return -1; + } + + + if (sizeof(uint64_t) != read(fd, &pfn_item, sizeof(uint64_t))) + { + printf("read %s failed", page_map_file); + + return -1; + } + + + if (0==(pfn_item & PFN_PRESENT_FLAG)) + { + printf("page is not present"); + + return -1; + } + + + *phy = (pfn_item & PFN_MASK)*page_size + vir % page_size; + + return 0; + + +} + +int main(int argc, char *argv[]) +{ + unsigned long viraddress; + unsigned long phyaddress; + + if(argc != 2) + { + printf("Usage : %s viraddress\n", argv[0]); + exit(-1); + } + + sscanf(argv[1], "%d", &viraddress); + + mem_addr_vir2phy(viraddress, &phyaddress); + + printf("%x", phyaddress); + + return EXIT_SUCCESS; +} diff --git a/study/engine/memoryEngine.c b/study/engine/memoryEngine.c new file mode 100644 index 0000000..f59e2c7 --- /dev/null +++ b/study/engine/memoryEngine.c @@ -0,0 +1,1376 @@ +/* +* Author: HIT CS HDMC team. +* Create: 2010-3-12 8:50 +* Last modified: 2010-6-13 14:06:20 +* Description: +* Memory fault injection engine running as a kernel module. +* This module will create "/proc/memoryEngine/" directory and 9 proc nodes. +* Write paramenters and request to these proc nodes and read the output from related proc node. +*/ + +#include "memoryEngine.h" + +/* +* proc entries +*/ +struct proc_dir_entry *dir = NULL; /// the directory of the MEMORY INJECT Moudle +struct proc_dir_entry *proc_pid = NULL; /// write only +struct proc_dir_entry *proc_va = NULL; /// write only +struct proc_dir_entry *proc_ctl = NULL; /// write only +struct proc_dir_entry *proc_kFuncName = NULL; /// write only +struct proc_dir_entry *proc_val = NULL; /// rw +struct proc_dir_entry *proc_signal = NULL; /// rw +struct proc_dir_entry *proc_pa = NULL; /// read only +struct proc_dir_entry *proc_taskInfo = NULL; /// read only + +/* +* proc node values +*/ +int pid; /// pid +unsigned long va; /// virtual Address +unsigned long pa; /// physical Addreess +int ctl; /// ctl +int signal; /// signal +char kFuncName[MAX_LINE]; /// kFuncName +long memVal; /// memVal + +unsigned long ack_pa; /// physical Address +unsigned long ack_va; /// virtual Address +int ack_signal; /// signal +int ret; /// return value +char taskInfo[PAGE_SIZE]; /// taskInfo + +/////////////////////////////////////////////// + +unsigned long userspace_phy_mem; /// user space physical memory +long orig_pa_data; /// origin data of the physics memory +long new_pa_data; /// the new data you want write to physics memory + +int faultInterval; + +/* +* kprobe +*/ +static struct kprobe kp_kFunc; + +struct jprobe jprobe1 = +{ + .entry = jforce_sig_info, + .kp = + { + .symbol_name = "force_sig_info", + }, +}; + +//时钟中断数计数 +static int count = 0; + +//保存原始代码 +static long orig_code = 0; + +/* +* process the request +*/ +void do_request(void) +{ + struct task_struct *task = NULL; + unsigned long pa = 0; + long kernel_va = 0; + int status; + + int temp = 0; + /// get a task's memory map information + if(ctl == REQUEST_TASK_INFO) + { + dbginfo("Rcv request:Get task info\n"); + + memset(taskInfo,'\0',sizeof(taskInfo)); + + if(pid <= 0) + { + ack_signal = ACK_TASK_INFO; + return; + } + task = findTaskByPid(pid); + + if( task != NULL ) + { + getTaskInfo(task, taskInfo, sizeof(taskInfo)); + } + else + { + dbginfo("No such process\n"); + } + ack_signal = ACK_TASK_INFO; + + return; + } + /// convert a process's linear address to physical address + else if(ctl == REQUEST_V2P) + { + task = findTaskByPid(pid); + if( task == NULL ) + { + dbginfo("No such process\n"); + ack_pa = -1; + ack_signal = ACK_V2P; + return; + } + if( task->mm == NULL ) + { + ack_pa = -1; + ack_signal = ACK_V2P; + return; + } + ack_pa = v2p(task->mm,va,&status); + if(ack_pa == FAIL) + { + dbginfo("No physical address\n"); + } + ack_signal = ACK_V2P; + return; + } + /// convert kernel virtual address to physical address + else if(ctl == REQUEST_KV2P) + { + ack_pa = kv2p(va,&status); + if(pa == FAIL) + { + dbginfo("No physical address\n"); + } + ack_signal = ACK_KV2P; + return; + } + /// get kernel function's addr(kernel virtual address) + else if(ctl == REQUEST_KFUNC_VA) + { + ack_va = kFunc2v(kFuncName); + ack_signal = ACK_KFUNC_VA; + return; + } + /// 请求读取内核函数起始地址内容 + else if(ctl == REQUEST_READ_KFUNC) + { + kernel_va = kFunc2v(kFuncName); + memVal = *((long *)kernel_va); + ack_signal = ACK_READ_KFUNC; + } + /// 请求改写内核函数起始地址内容 + else if(ctl == REQUEST_WRITE_KFUNC) + { + //利用kprobe,在第一次调用do_timer()时,注入故障 + int ret; + count = 0; + if(strlen(kFuncName) > 0) + { + faultInterval = 1; //故障仅持续一个时钟周期 + kp_kFunc.addr = 0; + kp_kFunc.symbol_name = kFuncName; + kp_kFunc.pre_handler = handler_pre_kFunc; + ret = register_kprobe(&kp_kFunc); + if(ret < 0) + { + dbginfo("Fained to register kprobe\n"); + ack_signal = ACK_WRITE_KFUNC; + return; + } + + // 等待故障注入结束 + dbginfo("start count\n"); + temp = 0; + + while(1) + { + if(count == -1) + { + unregister_kprobe(&kp_kFunc); + dbginfo("recovery\n"); + break; + } + if(temp == -1) + { + break; + } + temp++; + //dbginfo("count:%d\n",count); + } + } + ack_signal = ACK_WRITE_KFUNC; + dbginfo("Success to inject MTTR fault\n"); + return; + } + +} + +struct dentry* file_entry(struct file *pfile) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) + + return pfile->f_path.dentry; + +#else + + return pfile->f_dentry; + +#endif + +} + +/* +* get a task's memory map information +*/ +int getTaskInfo(struct task_struct *pTask, char *pData, int length) +{ + struct mm_struct *pMM; // struct mm_struct is defined in `include/linux/mm_types.h` + struct vm_area_struct *pVMA; + struct vm_area_struct *p; + struct dentry * pPath = NULL; + char *info = pData; + + char file[MAX_LINE]; + char *end, *start; + + long phy_addr; + unsigned long start_va, end_va; + int status; + + if(pTask == NULL) { return FAIL; } + if((pMM = pTask->mm) == NULL) { return FAIL; } + + memset(pData, '\0', length); + + + // 前19个字段是关于进程内存信息的总体信息 + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->total_vm, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->locked_vm, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->shared_vm, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->exec_vm, DELIMITER); + + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->stack_vm, DELIMITER); + +/// modify by gatieme for system porting NeoKylin-linux-3.14/16 +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 7, 0) + // error: ‘struct mm_struct’ has no member named ‘reserved_vm’ + // + // 从linux 3.7.0开始内核不再支持RESERVED_VM + // struct mm_struct 也没有了reserved_mm字段 + // struct vm_area_struct结构体中flag标志使用值 VM_RESERVED -=> (VM_DONTEXPAND | VM_DONTDUMP) + // + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->reserved_vm, DELIMITER); +#endif + + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->def_flags, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->nr_ptes, DELIMITER); + + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->start_code, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->end_code, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->start_data, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->end_data, DELIMITER); + + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->start_brk, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->brk, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->start_stack, DELIMITER); + + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->arg_start, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->arg_end, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->env_start, DELIMITER); + safe_sprintf(pData, length, info+strlen(info), "%lx%c", pMM->env_end, DELIMITER); + + pVMA = pMM->mmap; + if(pVMA == NULL) + { + return OK; + } + for(p = pVMA; p != NULL; p = p->vm_next) + { + // 起始地址 + safe_sprintf(pData, length, info + strlen(info), "%lx %lx ", p->vm_start, p->vm_end); + + // 属性 + if(p->vm_flags & VM_READ) + { + safe_sprintf(pData, length, info+strlen(info), "r"); + } + else + { + safe_sprintf(pData, length, info+strlen(info), "-"); + } + + if(p->vm_flags & VM_WRITE) + { + safe_sprintf(pData, length, info+strlen(info), "w"); + } + else + { + safe_sprintf(pData, length, info+strlen(info), "-"); + } + + if(p->vm_flags & VM_EXEC) + { + safe_sprintf(pData, length, info+strlen(info), "x"); + } + else + { + safe_sprintf(pData, length, info+strlen(info), "-"); + } + + if(p->vm_flags & VM_SHARED) + { + safe_sprintf(pData, length, info+strlen(info), "s"); + } + else + { + safe_sprintf(pData, length, info+strlen(info), "p"); + } + + // 对应文件名 + if(p->vm_file != NULL) + { + // i find in linux-kernel-3.16 + // http://lxr.free-electrons.com/source/include/linux/fs.h?v=3.16#L827 + // struct path f_path; + // #define f_dentry f_path.dentry + struct dentry *den = file_entry(p->vm_file); + + //if(p->vm_file->f_path.dentry != NULL) + if(den != NULL) + { + safe_sprintf(pData, length, info+strlen(info), " "); + memset(file,'\0',sizeof(file)); + //for(pPath = p->vm_file->f_path.dentry; + for(pPath = den; + pPath != NULL; + pPath = pPath->d_parent) + { + + if(strcmp(pPath->d_name.name, "/") != 0) + { + strcpy(file + strlen(file), pPath->d_name.name); + strcpy(file + strlen(file), "/"); + continue; + } + break; + } + do + { + end = file + strlen(file) - 1; + for(start = end - 1; *start != '/' && start > file; start--); + if(*start == '/') {start++;} + *end = '\0'; + + safe_sprintf(pData, length, info+strlen(info), "/%s", start); + *start = '\0'; + } while(start > file); + } + } + safe_sprintf(pData, length, info+strlen(info), "%c", DELIMITER); + + //对应物理地址页 + start_va = p->vm_start; + end_va = p->vm_end; + while(end_va > start_va) + { + safe_sprintf(pData, length, info+strlen(info), "%lx-%lx\t", start_va, start_va + PAGE_SIZE); + phy_addr = v2p(pMM, start_va, &status); + if(phy_addr != FAIL) + { + safe_sprintf(pData, length, info+strlen(info), "va:0x%lx <--> pa:0x%lx", start_va, phy_addr); + } + start_va += PAGE_SIZE; + safe_sprintf(pData, length, info+strlen(info), "%c", DELIMITER); + } + + safe_sprintf(pData, length, info+strlen(info), "%c", DELIMITER); + } + + dbginfo("get task info success...\n"); + return OK; +} + +/* +* +*/ +static int handler_pre_kFunc(struct kprobe *p, struct pt_regs *regs) +{ + unsigned long va; + va = (unsigned long)p->addr; + if(va <= 0) { return OK; } + + //第一次触发 + if(count == 0) + { + //读取前64字节,注入故障 + orig_code = *((long *)va); + //_inject_fault(va,memVal); + *((long *)va) = memVal; //故障 + return OK; + } + count ++; + //到达结束时间 + if(count == faultInterval + 1) + { + //恢复code + *((long *)va) = orig_code; + count = -1; + } + return OK; +} + +/* +* find_task_by_pid maybe not supported +* O(n) is fine :) +*/ +struct task_struct * findTaskByPid(pid_t pid) +{ + struct task_struct *task = NULL; + + // Traversing the process in the system to find the PID + // add by gatieme @2016-03-20 + for_each_process(task) + { + if(task->pid == pid) + { + dbginfo("find task by pid = %d\n", pid); + return task; + } + } + return NULL; +} + +/** add by gatieme */ +/* + * + */ +long readPhysicsAddress(unsigned long pa, int *pStatus) +{ + long res = FAIL; + //long *point = (long *)pa; + res = *(long *)pa; + dbgprint("physics address : 0x%lx, data : 0x%lx", pa, res); + + return res; +} + +long writePhysicsAddress(unsigned long pa, int *pStatus) +{ +} + + +/* +* convert a process's linear address to physical address +*/ +long v2p(struct mm_struct *pMM,unsigned long va,int *pStatus) +{ + pte_t *pte = NULL; + unsigned long phyaddress = FAIL; + + pte = getPte(pMM, va); + if(pte != NULL) + { + phyaddress = (pte_val(*pte) & PAGE_MASK) | (va & ~PAGE_MASK); + } + return phyaddress; +} + +/* +* convert kernel virtual address to physical address +*/ +long kv2p(unsigned long va,int *pStatus) +{ + if(va < 0) + return FAIL; + if(__pa(va) >= 0) + return __pa(va); + return FAIL; +} + +/* +* get kernel function's addr(kernel virtual address) +* the kernel function should be looked up in the System.map +*/ +static struct kprobe kp; +long kFunc2v(char *funcName) +{ + int ret; + unsigned long va; + + kp.addr = 0; + kp.symbol_name = funcName; + ret = register_kprobe(&kp); + if(ret < 0) + { + dbginfo("Fained to register kprobe\n"); + return FAIL; + } + va = (unsigned long)kp.addr; + unregister_kprobe(&kp); + if(va == 0) + return FAIL; + return va; +} + + + +/* +* +*/ +struct vm_area_struct * getVMA(struct mm_struct *pMM,unsigned long va) +{ + struct vm_area_struct *p; + if(pMM == NULL) return NULL; + p = pMM->mmap; + if(p == NULL) return NULL; + + for(; p != NULL; p = p->vm_next) + { + if( va >= p->vm_start && va < p->vm_end ) + { + return p; + } + } + return NULL; +} + +/* +* +*/ +pte_t * getPte(struct mm_struct *pMM, unsigned long va) +{ + pgd_t *pgd = NULL; + pmd_t *pmd = NULL; + pud_t *pud = NULL; + pte_t *pte = NULL; + + ///get the pdg entry pointer + pgd = pgd_offset(pMM, va); + if(pgd_none(*pgd)) { return NULL; } + + pud = pud_offset(pgd,va); + if(pud_none(*pud)) { return NULL; } + + pmd = pmd_offset(pud,va); + if(pmd_none(*pmd)) { return NULL; } + + pte = pte_offset_kernel(pmd,va); + if(pte_none(*pte)) { return NULL; } + if(!pte_present(*pte)) { return NULL; } + return pte; +} + +/* +* +*/ +int setVMAFlags(struct mm_struct *pMM,unsigned long va,int *pStatus,int flags) +{ + struct vm_area_struct *p; + p = getVMA(pMM,va); + if(p == NULL) return FAIL; + + if(flags > 0) + { + p->vm_flags |= VM_WRITE; + p->vm_flags |= VM_SHARED; + } + if(flags == 0) + { + p->vm_flags &= ~VM_WRITE; + p->vm_flags &= ~VM_SHARED; + } + else { return FAIL; } + return OK; +} + +/* +* +*/ +int setPageFlags(struct mm_struct *pMM,unsigned long va,int *pStatus,int flags) +{ + pte_t *pte = NULL; + pte_t ret; + pte = getPte(pMM, va); + if( pte == NULL ) { return FAIL; } + if(flags > 0) + { + ret = pte_mkwrite(*pte); + } + else if(flags == 0) + { + ret = pte_wrprotect(*pte); + } + else { return FAIL; } + return OK; +} + +/* +* +*/ +int proc_write_pid( struct file *file, + const char __user *buffer, + unsigned long count, + void * data) +{ + int iRet; + char sPid[MAX_LINE]; + + if(count <= 0) + { + return FAIL; + } + + memset(sPid, '\0', sizeof(sPid)); + ///////////////////////////////////////////////////////////////////// + // + // copy_from_user函数的目的是从用户空间拷贝数据到内核空间, + // 失败返回没有被拷贝的字节数,成功返回0. + // 这么简单的一个函数却含盖了许多关于内核方面的知识, + // 比如内核关于异常出错的处理. + // 从用户空间拷贝数据到内核中时必须很小心, + // 假如用户空间的数据地址是个非法的地址,或是超出用户空间的范围, + // 或是那些地址还没有被映射到,都可能对内核产生很大的影响, + // 如oops,或被造成系统安全的影响. + // 所以copy_from_user函数的功能就不只是从用户空间拷贝数据那样简单了, + // 他还要做一些指针检查连同处理这些问题的方法. + // + // 函数原型在[arch/i386/lib/usercopy.c]中 + // unsigned long + // copy_from_user( void *to, + // const void __user *from, + // unsigned long n) + // + ///////////////////////////////////////////////////////////////////// + // + // 将用户空间中, 地址buffr指向的count个数据拷贝到内核空间地址sPid中 + iRet = copy_from_user(sPid, buffer, count); + if(iRet != 0) + { + dbginfo("Error when copy_from_user...\n"); + return FAIL; + } + + iRet = sscanf(sPid, "%d", &pid); // 将读出来的数据sPid赋值给模块的全局变量pid + if(iRet != 1) + { + return FAIL; + } + dbginfo("Rcv pid:%d\n",pid); + + return count; +} + +/* +* +*/ +int proc_read_virtualAddr( char * page, + char **start, + off_t off, + int count, + int * eof, + void * data) +{ + int iLen; + + iLen = sprintf(page, "%lx", ack_va); + + + return iLen; +} + +/* +* +*/ +int proc_write_virtualAddr( struct file *file, + const char *buffer, + unsigned long count, + void * data) +{ + int iRet; + char sVa[MAX_LINE]; + + if(count <= 0) + { + return FAIL; + } + + memset(sVa, '\0', sizeof(sVa)); + + iRet = copy_from_user(sVa, buffer, count); + if(iRet) + { + return FAIL; + } + + iRet = sscanf(sVa,"%lx",&va); + if(iRet != 1) + { + return FAIL; + } + + dbginfo("Rcv virtual addr:0x%lx\n",va); + + return count; +} + +/* +* +*/ +int proc_write_ctl( struct file *file, + const char *buffer, + unsigned long count, + void * data) +{ + int iRet; + char sCtl[MAX_LINE]; + + if(count <= 0) + { + return FAIL; + } + + memset(sCtl, '\0', sizeof(sCtl)); + + iRet = copy_from_user(sCtl, buffer, count); + if(iRet) + { + return FAIL; + } + + iRet = sscanf(sCtl,"%d",&ctl); + if(iRet != 1) + { + return FAIL; + } + + do_request(); + + return count; +} + +/* +* +*/ +int proc_read_signal( char * page, + char **start, + off_t off, + int count, + int * eof, + void * data) +{ + int iLen; + + iLen = sprintf(page, "%d", ack_signal); + + return iLen; +} + +/* +* +*/ +int proc_write_signal( struct file *file, + const char *buffer, + unsigned long count, + void * data) +{ + int iRet; + char sSignal[MAX_LINE]; + + if(count <= 0) + { + return FAIL; + } + + memset(sSignal, '\0', sizeof(sSignal)); + iRet = copy_from_user(sSignal, buffer, count); + if(iRet) + { + return FAIL; + } + + iRet = sscanf(sSignal,"%d",&signal); + if(iRet != 1) + { + return FAIL; + } + + dbginfo("Rcv signal:%d\n",signal); + + return count; +} + +/* +* +*/ +int proc_read_pa(char * page,char **start, off_t off, int count, int * eof,void * data) +{ + int iLen; + iLen = sprintf(page, "%lx", ack_pa); + return iLen; +} + +/* +* +*/ +int proc_write_pa(struct file *file,const char *buffer,unsigned long count,void * data) +{ + int iRet; + char sPa[MAX_LINE]; + + if(count <= 0) { return FAIL; } + memset(sPa, '\0', sizeof(sPa)); + iRet = copy_from_user(sPa, buffer, count); + if(iRet) { return FAIL; } + iRet = sscanf(sPa,"%lx",&pa); + if(iRet != 1) { return FAIL; } + dbginfo("Rcv pa:0x%lx\n",pa); + return count; +} + +/* +* +*/ +int proc_write_kFuncName(struct file *file,const char *buffer,unsigned long count,void * data) +{ + int iRet; + if(count <= 0) { return FAIL; } + memset(kFuncName, '\0', sizeof(kFuncName)); + iRet = copy_from_user(kFuncName, buffer, count); + if(iRet) { return FAIL; } + //remove '\n' + if(kFuncName[strlen(kFuncName) - 1] == '\n') + { + kFuncName[strlen(kFuncName) - 1] = '\0'; + } + dbginfo("Rcv kernel func name:%s\n",kFuncName); + return count; +} + +/* +* +*/ +int proc_read_taskInfo(char * page,char **start, off_t off, int count, int * eof,void * data) +{ + int iLen; + iLen = sprintf(page, "%s", taskInfo); + return iLen; +} + +/* +* +*/ +int proc_write_memVal(struct file *file,const char *buffer,unsigned long count,void * data) +{ + int iRet; + char sMemVal[MAX_LINE]; + + if(count <= 0) + { + return FAIL; + } + + memset(sMemVal, '\0', sizeof(sMemVal)); + iRet = copy_from_user(sMemVal, buffer, count); + if(iRet) + { + return FAIL; + } + + iRet = sscanf(sMemVal,"%lx",&memVal); + if(iRet != 1) + { + return FAIL; + } + + dbginfo("Rcv memVal:0x%lx\n",memVal); + return count; +} + +/* +* +*/ +int proc_read_memVal( char * page, + char **start, + off_t off, + int count, + int * eof, + void * data) +{ + int iLen; + iLen = sprintf(page, "%lx", memVal); + return iLen; +} + +/* +* init memory fault injection module +* 初始化内存注入故障模块 +* +* 使用proc_mkdir()创建一个dir = /proc/memoryEngine +* 再利用create_proc_read_entry()函数创建一个processinfo文件。 +* 我们从模块里面获取的信息都将写入到这些文件中。 +* +*/ +static int __init initME(void) +{ + /* + * create a direntory named "memoryEngine" in /proc for the moudles + * as the interface between the kernel and the user program. + * + */ + dir = proc_mkdir("memoryEngine", NULL); + if(dir == NULL) + { + dbginfo("Can't create /proc/memoryEngine/\n"); + return FAIL; + } + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) + /// modify by gatieme for system porting NeoKylin-linux-3.14/16 + /// error: dereferencing pointer to incomplete type + dir->owner = THIS_MODULE; +#endif + + + /// modify by gatieme for system porting NeoKylin-linux-3.14/16 @ 2016--03-28 20:08 + /* + * == + * write in STACK_OVER_FLOW http://stackoverflow.com/questions/26808325/implicit-declaration-of-function-create-proc-entry + * == + * + * proc filesystem has been refactored in 3.10, + * the function `create_proc_entry` has been removed, + * you should use the full featured `proc_create function` family. + * + * Note that the signatures are different, you can find them in LXR + * 3.10 version: http://lxr.free-electrons.com/source/include/linux/proc_fs.h?v=3.10 + * 3.9 version: http://lxr.free-electrons.com/source/include/linux/proc_fs.h?v=3.9 + * + * You can find greater explanation of using full featured /proc functions in the book Linux Device Drivers 4, + * or, if you want shorter solution, check this link (https://github.com/jesstess/ldd4/blob/master/scull/main.c) + * where you can see how the struct file_operations has been used. You do not have to setup to all fields of the struct. + * + * but the function remove_proc_remove, you can do nothing for it, becase there are tow function for it + * static inline void proc_remove(struct proc_dir_entry *de) {} + * #define remove_proc_entry(name, parent) do {} while (0) + */ + + /// create a file named "pid" in direntory +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 10, 0) + + proc_pid = create_proc_entry("pid", PERMISSION, dir); + + if(proc_pid == NULL) + { + dbginfo("Can't create /proc/memoryEngine/pid\n"); + + goto create_pid_failed; + } + proc_pid->write_proc = proc_write_pid; /// write only +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) + proc_pid->owner = THIS_MODULE; +#endif +#else + static const struct file_operations pid_fops = + { + .owner = THIS_MODULE, + // .read = proc_write_read, + .write = proc_write_pid, /* write only */ + }; + + proc_pid = proc_create("pid", PERMISSION, dir, &pid_fops); + + if(proc_pid == NULL) + { + dbginfo("Can't create /proc/memoryEngine/pid\n"); + + goto create_pid_failed; + } + +#endif + + /// create a file named "virtualAddr" in direntory +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 10, 0) + + proc_va = create_proc_entry("virtualAddr", PERMISSION, dir); + if(proc_va == NULL) + { + dbginfo("Can't create /proc/memoryEngine/virtualAddr\n"); + + goto create_va_failed; + } + proc_va->read_proc = proc_read_virtualAddr; // can read + proc_va->write_proc = proc_write_virtualAddr; // can write + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) + proc_va->owner = THIS_MODULE; +#endif + +#else + static const struct file_operations va_fops = + { + .owner = THIS_MODULE, + .read = proc_read_virtualAddr, // can read + .write = proc_write_virtualAddr, // can write + }; + + proc_va = proc_create("virtualAddr", PERMISSION, dir, &va_fops); + + if(proc_va == NULL) + { + dbginfo("Can't create /proc/memoryEngine/virtualAddr\n"); + + goto create_va_failed; + } + + +#endif + + /// create a file named "ctl" in direntory +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 10, 0) + + proc_ctl = create_proc_entry("ctl", PERMISSION, dir); + if(proc_ctl == NULL) + { + dbginfo("Can't create /proc/memoryEngine/ctl\n"); + + goto create_ctl_failed; + + return FAIL; + } + + proc_ctl->write_proc = proc_write_ctl; // write only +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) + proc_ctl->owner = THIS_MODULE; +#endif + +#else + + static const struct file_operations ctl_fops = + { + .owner = THIS_MODULE, + //.read = proc_read_ctl, // can read + .write = proc_write_ctl, // write only + }; + + proc_ctl = proc_create("ctl", PERMISSION, dir, &ctl_fops); + + if(proc_ctl == NULL) + { + dbginfo("Can't create /proc/memoryEngine/ctl\n"); + + goto create_ctl_failed; + } + else + { + dbginfo("Create /proc/memoryEngine/ctl success...\n"); + } + +#endif + + /// create a file named "signal" in direntory +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 10, 0) + + proc_signal = create_proc_entry("signal", PERMISSION, dir); + + if(proc_signal == NULL) + { + dbginfo("Can't create /proc/memoryEngine/signal\n"); + + goto create_signal_failed; + } + proc_signal->read_proc = proc_read_signal; // can read + proc_signal->write_proc = proc_write_signal; // can write + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) + proc_signal->owner = THIS_MODULE; +#endif + +#else + + static const struct file_operations signal_fops = + { + .owner = THIS_MODULE, + .read = proc_read_signal, // can read + .write = proc_write_signal, // can write + }; + + proc_signal = proc_create("signal", PERMISSION, dir, &signal_fops); + + if(proc_signal == NULL) + { + dbginfo("Can't create /proc/memoryEngine/signal\n"); + + goto create_signal_failed; + } + else + { + dbginfo("Create /proc/memoryEngine/signal success\n"); + } +#endif + + /// create a file named "physicalAddr" in direntory +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 10, 0) + + proc_pa = create_proc_entry("physicalAddr", PERMISSION, dir); + if(proc_pa == NULL) + { + dbginfo("Can't create /proc/memoryEngine/physicalAddr\n"); + + goto create_pa_failed; + } + + proc_pa->read_proc = proc_read_pa; // can read + proc_pa->write_proc = proc_write_pa; // can write + +#else + + static const struct file_operations pa_fops = + { + .owner = THIS_MODULE, + .read = proc_read_pa, // read only + .write = proc_write_pa, // write only + }; + + proc_pa = proc_create("physicalAddr", PERMISSION, dir, &pa_fops); + + if(proc_pa == NULL) + { + dbginfo("Can't create /proc/memoryEngine/physicalAddr\n"); + + goto create_pa_failed; + } + +#endif + + + /// create a file named "kFuncName" in direntory +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 10, 0) + + proc_kFuncName = create_proc_entry("kFuncName", PERMISSION, dir); + + if(proc_kFuncName == NULL) + { + dbginfo("Can't create /proc/memoryEngine/kFuncName\n"); + + goto create_kFuncName_failed; + + } + proc_kFuncName->write_proc = proc_write_kFuncName; // write only + +#else + + static const struct file_operations kFuncName_fops = + { + .owner = THIS_MODULE, + //.read = proc_read_kFuncName, // read only + .write = proc_write_kFuncName, // write only + }; + + proc_kFuncName = proc_create("kFuncName", PERMISSION, dir, &kFuncName_fops); + + if(proc_kFuncName == NULL) + { + dbginfo("Can't create /proc/memoryEngine/kFuncName\n"); + + goto create_kFuncName_failed; + } + +#endif + + /// create a file named "taskInfo" in direntory +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 10, 0) + + proc_taskInfo = create_proc_entry("taskInfo", PERMISSION, dir); + + if(proc_taskInfo == NULL) + { + dbginfo("Can't create /proc/memoryEngine/taskInfo\n"); + + goto create_taskInfo_failed; + } + proc_taskInfo->read_proc = proc_read_taskInfo; // read only + +#else + + static const struct file_operations taskInfo_fops = + { + .owner = THIS_MODULE, + .read = proc_read_taskInfo, // read only + //.write = proc_write_taskInfo, // write only + }; + + proc_taskInfo = proc_create("taskInfo", PERMISSION, dir, &taskInfo_fops); + + if(proc_taskInfo == NULL) + { + dbginfo("Can't create /proc/memoryEngine/taskIndfo\n"); + + goto create_taskInfo_failed; + } +#endif + + + /// create a file named "memVal" in direntory +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 10, 0) + + proc_val = create_proc_entry("memVal", PERMISSION, dir); + + if(proc_val == NULL) + { + dbginfo("Can't create /proc/memoryEngine/memVal\n"); + + goto create_val_failed; + } + + proc_val->write_proc = proc_write_memVal; // can write + proc_val->read_proc = proc_read_memVal; // can read + + +#else + + static const struct file_operations val_fops = + { + .owner = THIS_MODULE, + .read = proc_read_memVal, // can read + .write = proc_write_memVal, // can write + }; + + proc_val = proc_create("memVal", PERMISSION, dir, &val_fops); + + if(proc_val == NULL) + { + dbginfo("Can't create /proc/memoryEngine/memVal\n"); + + goto create_val_failed; + } +#endif + + ret = register_jprobe(&jprobe1); + if (ret < 0) + { + printk("register_jprobe jprobe1 failed, returned %d\n", ret); + return ret; + } + printk("Planted jprobe at force_sig_info: %p\n", jprobe1.kp.addr); + + dbginfo("Memory engine module init\n"); + return OK; + + +// remove the proc files +create_val_failed : + remove_proc_entry("kFuncName", dir); + +create_kFuncName_failed : + remove_proc_entry("taskInfo", dir); + +create_taskInfo_failed : + remove_proc_entry("physicalAddr", dir); + +create_pa_failed : + remove_proc_entry("signal", dir); + +create_signal_failed : + remove_proc_entry("ctl", dir); + +create_ctl_failed : + remove_proc_entry("virtualAddr", dir); + +create_va_failed : + remove_proc_entry("pid", dir); + +create_pid_failed : + remove_proc_entry("memoryEngine", NULL); + + return FAIL; + +} + +/// modify by gatieme for system porting NeoKylin-linux-3.14/16 @ 2016--03-28 20:08 +// invalid storage class for function ‘jforce_sig_info’ +static int jforce_sig_info(int sig, struct siginfo *info, struct task_struct *t) +{ + printk("MemSysFI: kernel is sending signal %d to process pid: %d, comm: %s\n",sig,t->pid,t->comm); +/* + if (f_inject == 'N') + { + jprobe_return(); + return 0; + } + + down_interruptible(&sem); + if ( addone(addone(inj_info.rear))==inj_info.front ) + { + */ + /*error:队列满*/ + /* + sprintf(inj_info.inj_log[inj_info.rear].msg,"caution : buf is full, messages have been dropped\n"); + } + else + { + inj_info.rear = addone(inj_info.rear); + sprintf(inj_info.inj_log[inj_info.rear].msg,"warning : kernel is sending signal %d to process pid: %d, comm: %s\n",sig,current->pid,current->comm); + //inj_info->inj_log[inj_info->rear ] = x ; + } + up(&sem); + */ + /* + if(message!=NULL) + { + for(i=0;i<256;i++) + message[i]='\0'; + + sprintf(message,"warning : kernel is sending signal %d to process pid: %d, comm: %s\n\0",sig,current->pid,current->comm); + } + else + return -1; + + + struct bufferList *buflist; + buflist = (struct bufferList *)kmalloc(sizeof(struct bufferList),GFP_KERNEL); + buflist->pNext = NULL; + buflist->buffer = message; + + down_interruptible(&sem); + if(Head==NULL) + { + Head = buflist; + Tail = Head; + } + else + { + Tail->pNext = buflist; + Tail = buflist; + } + flag = 1; + up(&sem); + */ + +// wake_up_interruptible(&wq2); + + jprobe_return(); + return 0; +} + +/* +* uninit memory fault injection module +*/ +static void __exit exitME(void) +{ + remove_proc_entry("pid", dir); + remove_proc_entry("virtualAddr", dir); + remove_proc_entry("ctl", dir); + remove_proc_entry("signal", dir); + remove_proc_entry("physicalAddr", dir); + remove_proc_entry("kFuncName", dir); + remove_proc_entry("taskInfo", dir); + remove_proc_entry("memVal", dir); + remove_proc_entry("memoryEngine", NULL); + unregister_jprobe(&jprobe1); + printk("jprobe at %p unregistered.\n", jprobe1.kp.addr); + dbginfo("Memory engine module exit\n"); +} + +module_init(initME); +module_exit(exitME); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Gatieme @ HIT CS HDMC team"); +MODULE_DESCRIPTION("Memory Engine Module."); + diff --git a/study/engine/memoryEngine.h b/study/engine/memoryEngine.h new file mode 100644 index 0000000..0d2e1ed --- /dev/null +++ b/study/engine/memoryEngine.h @@ -0,0 +1,121 @@ +/* +* Author: HIT CS HDMC team. +* Create: 2010-3-12 8:20:01 +* Last modified: 2010-6-13 14:13:47 +*/ + +#ifndef _MEMORY_ENGINE_H +#define _MEMORY_ENGINE_H + +/* +* common include header files +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + + +#define MAX_LINE 256 /// max length of a line +#define DELIMITER '\n' /// the char is used to split the taskinfo +#define PERMISSION 0644 /// proc node permission +/* +* return values +*/ +#define OK 0 +#define FAIL -1 +#define PGD_NONE -2 +#define PUD_NONE -3 +#define PMD_NONE -4 +#define PTE_NONE -5 +#define PTE_NOT_PRESENT -6 + + + +/* +* request command +*/ +#define REQUEST_TASK_INFO 1 /// get a task's memory map information +#define REQUEST_V2P 2 /// convert a process's linear address to physical address +#define REQUEST_KV2P 3 /// convert kernel virtual address to physical address +#define REQUEST_KFUNC_VA 4 /// get kernel function's addr(kernel virtual address) +#define REQUEST_READ_KFUNC 5 /// 璇锋眰璇诲彇鍐呮牳鍑芥暟璧峰鍦板潃鍐呭 +#define REQUEST_WRITE_KFUNC 6 /// 璇锋眰鏀瑰啓鍐呮牳鍑芥暟璧峰鍦板潃鍐呭 +///#define REQUEST_WRITE 10 /// 璇锋眰鏀瑰啓鎸囧畾鐗╃悊鍦板潃鍐呭锛屾敼涓虹敤鎴锋佸疄鐜版鍔熻兘 +///#define REQUEST_MEM 11 /// 璇锋眰鑾峰彇鍏ㄩ儴鐗╃悊鍐呭瓨淇℃伅 +///#define REQUEST_ADDR_STOP 12 /// + +/* +* ack signals +*/ +#define ACK_TASK_INFO REQUEST_TASK_INFO +#define ACK_V2P REQUEST_V2P +#define ACK_KV2P REQUEST_KV2P +#define ACK_KFUNC_VA REQUEST_KFUNC_VA +#define ACK_READ_KFUNC REQUEST_READ_KFUNC +#define ACK_WRITE_KFUNC REQUEST_WRITE_KFUNC +///#define REQUEST_WRITE REQUEST_WRITE +///#define ACK_MEM REQUEST_MEM +///#define ACK_ADDR_STOP REQUEST_ADDR_STOP + +/* +* utility functions +*/ +static int handler_pre_kFunc(struct kprobe *p, struct pt_regs *regs); + +struct task_struct *findTaskByPid(pid_t pid); + +long v2p(struct mm_struct *pMM,unsigned long va,int *pStatus); + +long kv2p(unsigned long va,int *pStatus); + +long kFunc2v(char *funcName); + +struct vm_area_struct * getVMA(struct mm_struct *pMM,unsigned long va); + +pte_t * getPte(struct mm_struct *pMM,unsigned long va); + +int setVMAFlags(struct mm_struct *pMM,unsigned long va,int *pStatus,int flags); + +int setPageFlags(struct mm_struct *pMM,unsigned long va,int *pStatus,int flags); + +int getTaskInfo(struct task_struct *pTask, char *pData, int length); + +/* +* proc entry function +*/ +int proc_write_pid(struct file *file,const char __user *buffer,unsigned long count,void * data); + +int proc_read_virtualAddr(char * page,char **start, off_t off, int count, int * eof,void * data); +int proc_write_virtualAddr(struct file *file,const char *buffer,unsigned long count,void * data); + +int proc_write_ctl(struct file *file,const char *buffer,unsigned long count,void * data); + +int proc_read_signal(char * page,char **start, off_t off, int count, int * eof,void * data); +int proc_write_signal(struct file *file,const char *buffer,unsigned long count,void * data); + +int proc_read_pa(char * page,char **start, off_t off, int count, int * eof,void * data); + +static int jforce_sig_info(int sig,struct siginfo *info,struct task_struct *t); + + +#endif + diff --git a/study/engine/mmap/2.4/Makefile b/study/engine/mmap/2.4/Makefile new file mode 100644 index 0000000..8385e36 --- /dev/null +++ b/study/engine/mmap/2.4/Makefile @@ -0,0 +1,5 @@ +CC=gcc +INCLUDEDIR = /home/linux/include/ +MODCFLAGS :=-Wall -O -DMODULE -D__KERNEL__ -DLINUX -I$(INCLUDEDIR) +map_driver.o: map_driver.c + $(CC) $(MODCFLAGS) -c map_driver.c diff --git a/study/engine/mmap/2.4/map_driver.c b/study/engine/mmap/2.4/map_driver.c new file mode 100644 index 0000000..7f0aa9f --- /dev/null +++ b/study/engine/mmap/2.4/map_driver.c @@ -0,0 +1,216 @@ +#define _VERSION__ +#include +#include +#if CONFIG_MODVERSIOINS==1 +#define MODVERSIONS +#include +#endif +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define MAPLEN (4096*10) +/* device open */ +int mapdrv_open(struct inode *inode,struct file *file); +/* device close */ +int mapdrv_release(struct inode *inode,struct file *file); +/*device mmap */ +int mapdrv_mmap(struct file *file,struct vm_area_struct *vma); + +/* vm area open */ +void map_vopen(struct vm_area_struct *vma); +/* vm area close */ +void map_vclose(struct vm_area_struct *vma); +/* vm area nopage */ +struct page *map_nopage(struct vm_area_struct *vma,unsigned long address,int write_access); + +static struct file_operations mapdrv_fops= +{ + owner : THIS_MODULE, + mmap : mapdrv_mmap, + open : mapdrv_open, + release:mapdrv_release, +}; + +static struct vm_operations_struct map_vm_ops= +{ + open : map_vopen, + close : map_vclose, + nopage: map_nopage, +}; + +static int *vmalloc_area = NULL; + +static int major; // major number of device + +volatile void *vaddr_to_kaddr(volatile void *address) +{ + pgd_t *pgd; pmd_t *pmd; pte_t *ptep, pte; + unsigned long va, ret = 0UL; + va=VMALLOC_VMADDR((unsigned long)address); + /* get the page directory. Use the kernel memory map. */ + pgd = pgd_offset_k(va); + /* check whether we found an entry */ + if (!pgd_none(*pgd)) + { + /* get the page middle directory */ + pmd = pmd_offset(pgd, va); + /* check whether we found an entry */ + if (!pmd_none(*pmd)) + { + /* get a pointer to the page table entry */ + ptep = pte_offset(pmd, va); + pte = *ptep; + /* check for a valid page */ + if (pte_present(pte)) + { + /* get the address the page is refering to */ + ret = (unsigned long)page_address(pte_page(pte)); + /* add the offset within the page to the page address */ ret |= (va & (PAGE_SIZE -1)); + } + } + } + return((volatile void *)ret); +} + + + +static int __init mapdrv_init(void) +{ + + unsigned long virt_addr; + if ((major=register_chrdev(0, "mapdrv", &mapdrv_fops))<0) + { + printk("mapdrv: unable to register character device\n"); + return (-EIO); + } + /* get a memory area that is only virtual contigous. */ + vmalloc_area=vmalloc(MAPLEN/*+2*PAGE_SIZE*/); + + + for (virt_addr=(unsigned long)vmalloc_area;virt_addr<(unsigned long)(&(vmalloc_area[MAPLEN/sizeof(int)]));virt_addr+=PAGE_SIZE) + { + + mem_map_reserve(virt_to_page(vaddr_to_kaddr((void *)virt_addr))); + } + /* set a hello message to kernel space for read by user */ + strcpy((char*)vmalloc_area,"hello world from kernel space !"); + + + printk("vmalloc_area at 0x%p (phys 0x%lx)\n", vmalloc_area, + virt_to_phys((void *)vaddr_to_kaddr(vmalloc_area))); + return(0); +} + + +static void __exit mapdrv_exit(void) +{ + unsigned long virt_addr; + /* unreserve all pages */ + for (virt_addr=(unsigned long)vmalloc_area;virt_addr<(unsigned long)(&(vmalloc_area[MAPLEN/sizeof(int)]));virt_addr+=PAGE_SIZE) + { + mem_map_unreserve(virt_to_page(vaddr_to_kaddr((void *)virt_addr))); + } + /* and free the two areas */ + if (vmalloc_area) + vfree(vmalloc_area); + /* unregister the device */ + unregister_chrdev(major, "mapdrv"); + return; + +} +/* device open method */ +int mapdrv_open(struct inode *inode, struct file *file) +{ + MOD_INC_USE_COUNT; + return(0); +} + +/* device close method */ +int mapdrv_release(struct inode *inode, struct file *file) +{ + MOD_DEC_USE_COUNT; + return(0); +} + +int mapdrv_mmap(struct file *file, struct vm_area_struct *vma) +{ + unsigned long offset = vma->vm_pgoff<vm_end - vma->vm_start; + if (offset & ~PAGE_MASK) + { + printk("offset not aligned: %ld\n", offset); + return -ENXIO; + } + if (size>MAPLEN) + { + printk("size too big\n"); + return(-ENXIO); + } + /* only support shared mappings.*/ + if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED)) + { + printk("writeable mappings must be shared, rejecting\n"); + return(-EINVAL); + } + /* do not want to have this area swapped out, lock it */ + vma->vm_flags |= VM_LOCKED; + if (offset == 0) + { + vma->vm_ops = &map_vm_ops; + /* call the open routine to increment the usage count */ + map_vopen(vma); + }else + { + printk("offset out of range\n"); + return -ENXIO; + } + return(0); +} +/* open handler for vm area */ +void map_vopen(struct vm_area_struct *vma) +{ + /* needed to prevent the unloading of the module while + somebody still has memory mapped */ + MOD_INC_USE_COUNT; +} + +/* close handler form vm area */ +void map_vclose(struct vm_area_struct *vma) +{ + MOD_DEC_USE_COUNT; +} + +/* page fault handler */ +struct page *map_nopage(struct vm_area_struct *vma, unsigned long address, int write_access) +{ + unsigned long offset; + unsigned long virt_addr; + /* determine the offset within the vmalloc'd area */ + offset = address - vma->vm_start + (vma->vm_pgoff<count)); + printk("map_drv: page fault for offset 0x%lx (kseg x%lx)\n",offset, virt_addr); + return(virt_to_page(virt_addr)); + +} + + + + +module_init(mapdrv_init); +module_exit(mapdrv_exit); diff --git a/study/engine/mmap/2.6/Makefile b/study/engine/mmap/2.6/Makefile new file mode 100644 index 0000000..856a740 --- /dev/null +++ b/study/engine/mmap/2.6/Makefile @@ -0,0 +1,21 @@ +# Makefile for the memory fault injection engine. +# +# Author: HIT CS HDMC team. +# Create: 2010-3-12 8:46 +# Last modified: 2010-6-13 13:55:29 +# Description: +# This program is loaded as a kernel(v2.6.18 or later) module. +# Use "make install" to load it into kernel. +# Use "make remove" to remove the module out of kernel. +# + +obj-m := map_driver.o +all: + make -C /lib/modules/`uname -r`/build M=`pwd` modules +install: + insmod memoryEngine.ko +remove: + rmmod memoryEngine +clean: + make -C /lib/modules/`uname -r`/build M=`pwd` clean + rm -f modules.order Module.symvers Module.markers diff --git a/study/engine/mmap/2.6/map_driver.c b/study/engine/mmap/2.6/map_driver.c new file mode 100644 index 0000000..b14c906 --- /dev/null +++ b/study/engine/mmap/2.6/map_driver.c @@ -0,0 +1,345 @@ +#define _VERSION__ + +#include +#include + +#if CONFIG_MODVERSIOINS==1 + + #define MODVERSIONS + #include + +#endif + +#include +#include +#include + +#include +#include +//#include +#include +#include +#include + +#define MAPLEN (4096*10) + + +/* + * 灏嗕唬鐮佷粠linux2.4绉绘鍒發inux2.6.* + * + * ==A== + * 2.4鍐呮牳涓紝妯″潡鑷韩閫氳繃 MOD_INC_USE_COUNT, MOD_DEC_USE_COUNT瀹忔潵绠$悊鑷繁琚娇鐢ㄧ殑璁℃暟銆 + * 2.6鍐呮牳鎻愪緵浜嗘洿鍋ュ.銆佺伒娲荤殑妯″潡璁℃暟绠$悊鎺ュ彛 try_module_get(&module), module_put(&module) + * 鍙栦唬2.4涓殑妯″潡浣跨敤璁℃暟绠$悊瀹忥紱妯″潡鐨勪娇鐢ㄨ鏁颁笉蹇呯敱鑷韩绠$悊锛 + * 鑰屼笖鍦ㄧ鐞嗘ā鍧椾娇鐢ㄨ鏁版椂鑰冭檻鍒 SMP涓嶱REEMPT鏈哄埗鐨勫奖鍝嶃 + * + * ==B== + * em_map_reserve鏄2.4鐨勫嚱鏁 鑰屽埌2.6琚玈etPageReserved鍙栦唬 + * */ + + +/* device open */ +int mapdrv_open(struct inode *inode,struct file *file); + +/* device close */ +int mapdrv_release(struct inode *inode,struct file *file); + +/*device mmap */ +int mapdrv_mmap(struct file *file,struct vm_area_struct *vma); + +/* vm area open */ +void map_vopen(struct vm_area_struct *vma); + +/* vm area close */ +void map_vclose(struct vm_area_struct *vma); + +/* vm area nopage */ +struct page *map_nopage(struct vm_area_struct *vma,unsigned long address,int write_access); + +static struct file_operations mapdrv_fops= +{ + owner : THIS_MODULE, + mmap : mapdrv_mmap, + open : mapdrv_open, + release:mapdrv_release, +}; + +static struct vm_operations_struct map_vm_ops= +{ + open : map_vopen, + close : map_vclose, + nopage: map_nopage, +}; + +static int *vmalloc_area = NULL; + +static int major; // major number of device + +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) + +volatile void *vaddr_to_kaddr(volatile void *address) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *ptep, pte; + + unsigned long va; + unsigned long ret = 0UL; + + va = VMALLOC_VMADDR((unsigned long)address); + + /* get the page directory. Use the kernel memory map. */ + pgd = pgd_offset_k(va); + /* check whether we found an entry */ + if (pgd_none(*pgd)) + { + return NULL; + } + + /* get the page upper directory */ + pud = pud_offset(pgd, va); + /* check whether we found an entry */ + if (pud_none(*pud)) + { + return NULL; + } + + + /* get the page middle directory */ + pmd = pmd_offset(pud, va); + /* check whether we found an entry */ + if (pmd_none(*pmd)) + { + return NULL; + } + + /* get a pointer to the page table entry */ + /*ptep = pte_offset(pmd, va); implicit declaration of function 鈥榩te_offset鈥檂. */ + ptep = pte_offset_kernel(pmd, va); + pte = *ptep; + + /* check for a valid page */ + if (pte_present(pte)) + { + + /* get the address the page is refering to */ + ret = (unsigned long)page_address(pte_page(pte)); + + /* add the offset within the page to the page address */ + ret |= (va & (PAGE_SIZE -1)); + } + + return((volatile void *)ret); +} + + + +static int __init mapdrv_init(void) +{ + unsigned long virt_addr; + if ((major = register_chrdev(0, "mapdrv", &mapdrv_fops)) < 0) + { + printk("mapdrv: unable to register character device\n"); + + return (-EIO); + } + + /* get a memory area that is only virtual contigous. */ + vmalloc_area = vmalloc(MAPLEN/* + 2 * PAGE_SIZE*/); + + + for (virt_addr = (unsigned long)vmalloc_area; + virt_addr < (unsigned long)(&(vmalloc_area[MAPLEN / sizeof(int)])); + virt_addr += PAGE_SIZE) + { + /* + error: implicit declaration of function 鈥榤em_map_reserve鈥 + `mem_map_reserve` can be found in linux-2.4, but not define in linux-2.6 + you can use `SetPageReserved` instead... + + #define SetPageReserved(page) set_bit(PG_reserved, &(page)->flags) + #define mem_map_reserve(p) set_bit(PG_reserved, &((p)->flags)) + + so the code + + mem_map_reserve(virt_to_page(vaddr_to_kaddr((void *)virt_addr))); + + use the next instead + + SetPageReserved(virt_to_page(vaddr_to_kaddr((void *)virt_addr))); + + it's the same to mem_map_unreserve + */ + SetPageReserved(virt_to_page(vaddr_to_kaddr((void *)virt_addr))); + } + + /* set a hello message to kernel space for read by user */ + strcpy((char*)vmalloc_area, "hello world from kernel space !"); + + + printk("vmalloc_area at 0x%p (phys 0x%lx)\n", + vmalloc_area, + virt_to_phys((void *)vaddr_to_kaddr(vmalloc_area))); + + + return (0); +} + + +static void __exit mapdrv_exit(void) +{ + unsigned long virt_addr; + + /* unreserve all pages */ + for (virt_addr = (unsigned long)vmalloc_area; + virt_addr < (unsigned long)(&(vmalloc_area[MAPLEN / sizeof(int)])); + virt_addr += PAGE_SIZE) + { + /* + * error: implicit declaration of function 鈥榤em_map_unreserve鈥檂. + * it's the same to mem_map_reserve + + so the code + + mem_map_unreserve(virt_to_page(vaddr_to_kaddr((void *)virt_addr))); + + use the next code instead... + + ClearPageReserved(virt_to_page(vaddr_to_kaddr((void *)virt_addr))); + */ + ClearPageReserved(virt_to_page(vaddr_to_kaddr((void *)virt_addr))); + } + /* and free the two areas */ + if (vmalloc_area) + { + vfree(vmalloc_area); + } + + /* unregister the device */ + unregister_chrdev(major, "mapdrv"); + + + return; + +} +/* device open method */ +int mapdrv_open(struct inode *inode, struct file *file) +{ +/* + the code in linux-2.4 + MOD_INC_USE_COUNT; + use the next instead... + try_module_get(THIS_MODULE); +*/ + try_module_get(THIS_MODULE); + return(0); +} + +/* device close method */ +int mapdrv_release(struct inode *inode, struct file *file) +{ + /* + the code in linux-2.4 + MOD_DEC_USE_COUNT; + use the next instead + module_put(THIS_MODULE); + */ + module_put(THIS_MODULE); + + return(0); +} + +int mapdrv_mmap(struct file *file, struct vm_area_struct *vma) +{ + unsigned long offset = vma->vm_pgoff<vm_end - vma->vm_start; + if (offset & ~PAGE_MASK) + { + printk("offset not aligned: %ld\n", offset); + return -ENXIO; + } + if (size>MAPLEN) + { + printk("size too big\n"); + return(-ENXIO); + } + /* only support shared mappings.*/ + if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED)) + { + printk("writeable mappings must be shared, rejecting\n"); + return(-EINVAL); + } + /* do not want to have this area swapped out, lock it */ + vma->vm_flags |= VM_LOCKED; + if (offset == 0) + { + vma->vm_ops = &map_vm_ops; + /* call the open routine to increment the usage count */ + map_vopen(vma); + }else + { + printk("offset out of range\n"); + return -ENXIO; + } + return(0); +} +/* open handler for vm area */ +void map_vopen(struct vm_area_struct *vma) +{ + /* needed to prevent the unloading of the module while + somebody still has memory mapped */ +// MOD_INC_USE_COUNT; + +/* + the code in linux-2.4 + MOD_INC_USE_COUNT; + use the next instead... + try_module_get(THIS_MODULE); +*/ + try_module_get(THIS_MODULE); +} + +/* close handler form vm area */ +void map_vclose(struct vm_area_struct *vma) +{ + + /* + the code in linux-2.4 + MOD_DEC_USE_COUNT; + use the next instead + module_put(THIS_MODULE); + */ + module_put(THIS_MODULE); +} + +/* page fault handler */ +struct page *map_nopage(struct vm_area_struct *vma, unsigned long address, int write_access) +{ + unsigned long offset; + unsigned long virt_addr; + + /* determine the offset within the vmalloc'd area */ + offset = address - vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT); + + /* translate the vmalloc address to kmalloc address */ + virt_addr = (unsigned long)vaddr_to_kaddr(&vmalloc_area[offset / sizeof(int)]); + if (virt_addr == 0UL) + { + return((struct page *)0UL); + } + + /* increment the usage count of the page */ + atomic_inc(&(virt_to_page(virt_addr)->_count)); + printk("map_drv: page fault for offset 0x%lx (kseg x%lx)\n",offset, virt_addr); + + return(virt_to_page(virt_addr)); + +} + + + + +module_init(mapdrv_init); +module_exit(mapdrv_exit); diff --git a/study/engine/mmap/2.6/maptest.c b/study/engine/mmap/2.6/maptest.c new file mode 100644 index 0000000..dcfd9d8 --- /dev/null +++ b/study/engine/mmap/2.6/maptest.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include +#define LEN (10*4096) + + + +int main(void) +{ + int fd; + unsigned int *vadr; + + if ((fd=open("mapfile", O_RDWR))<0) + { + perror("open"); + exit(-1); + } + (char *)vadr = (char*)mmap(0, LEN, PROT_READ, MAP_SHARED, fd, 0); + + if (vadr == MAP_FAILED) + { + perror("mmap"); + exit(-1); + } + + printf("%s\n",vadr); + close(fd); + return(0); +} + + diff --git a/study/engine/mmap/README.mk b/study/engine/mmap/README.mk new file mode 100644 index 0000000..efe50fa --- /dev/null +++ b/study/engine/mmap/README.mk @@ -0,0 +1,28 @@ +绋嬪簭缁勬垚 +map_driver.c 瀹冩槸浠ユā鍧楀舰寮忓姞杞界殑铏氭嫙瀛楃椹卞姩绋嬪簭銆 +璇ラ┍鍔ㄨ礋璐e皢涓瀹氶暱鐨勫唴鏍歌櫄鎷熷湴鍧(vmalloc鍒嗛厤鐨)鏄犲皠鍒拌澶囨枃浠朵笂銆 + +鍏朵腑涓昏鐨勫嚱鏁版湁鈥斺攙address_to_kaddress锛堬級璐熻矗瀵箆malloc鍒嗛厤鐨勫湴鍧杩涜椤佃〃瑙f瀽,浠 +鎵惧埌瀵瑰簲鐨勫唴鏍哥墿鐞嗘槧灏勫湴鍧锛坘malloc鍒嗛厤鐨勫湴鍧锛夛紱 +map_nopage()璐熻矗鍦ㄨ繘绋嬭闂竴涓綋鍓嶅苟涓嶅瓨鍦ㄧ殑VMA椤垫椂锛屽鎵捐鍦板潃瀵瑰簲鐨勭墿鐞嗛〉锛屽苟杩斿洖璇ラ〉鐨勬寚閽堛 + + +test.c 瀹冨埄鐢ㄤ笂杩伴┍鍔ㄦā鍧楀搴旂殑璁惧鏂囦欢鍦ㄧ敤鎴风┖闂磋鍙栬鍙栧唴鏍稿唴瀛樸傜粨鏋滃彲浠ョ湅鍒板唴鏍歌櫄鎷熷湴鍧鐨勫唴瀹癸紙ok!锛夛紝琚樉绀哄湪浜嗗睆骞曚笂銆 + +鎵ц姝ラ + +缂栬瘧map_driver.c涓簃ap_driver.o妯″潡,鍏蜂綋鍙傛暟瑙丮akefile + +鍔犺浇妯″潡 锛歩nsmod map_driver.o + 鐢熸垚瀵瑰簲鐨勮澶囨枃浠 + +1 鍦/proc/devices涓嬫壘鍒癿ap_driver瀵瑰簲鐨勮澶囧懡鍜岃澶囧彿锛歡rep mapdrv /proc/devices + +2 寤虹珛璁惧鏂囦欢mknod mapfile c 254 0 锛堝湪鎴戠殑绯荤粺閲岃澶囧彿涓254锛 + +鍒╃敤maptest璇诲彇mapfile鏂囦欢锛屽皢鍙栬嚜鍐呮牳鐨勪俊鎭墦鍗板埌灞忓箷涓娿 + + +鍏ㄩ儴绋嬪簭涓嬭浇 mmap.tar 锛堟劅璋artin Frey锛岃绋嬪簭鐨勪富浣撳嚭鑷粬鐨勭伒鎰燂級 +return(0); +http://blog.chinaunix.net/uid-24227137-id-3723898.html diff --git a/study/engine/mmap/mem.c b/study/engine/mmap/mem.c new file mode 100644 index 0000000..d7f5b91 --- /dev/null +++ b/study/engine/mmap/mem.c @@ -0,0 +1,105 @@ +/***************************************************************** +鏂囦欢鍚嶏細mem.c +杈撳叆鍙傛暟锛 +pid 鎺ユ敹寰呮煡璇㈣繘绋嬬殑PID +va 鎺ユ敹寰呮煡璇㈢殑铏氭嫙鍦板潃 +*****************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +MODULE_LICENSE("GPL"); +static int pid; +static unsigned long va; + +module_param(pid,int,0644); +module_param(va,ulong,0644); + +static int find_pgd_init(void) +{ + unsigned long pa = 0; + struct task_struct *pcb_tmp = NULL; + pgd_t *pgd_tmp = NULL; + pud_t *pud_tmp = NULL; + pmd_t *pmd_tmp = NULL; + pte_t *pte_tmp = NULL; + + printk(KERN_INFO"PAGE_OFFSET = 0x%lx\n",PAGE_OFFSET); + printk(KERN_INFO"PGDIR_SHIFT = %d\n",PGDIR_SHIFT); + printk(KERN_INFO"PUD_SHIFT = %d\n",PUD_SHIFT); + printk(KERN_INFO"PMD_SHIFT = %d\n",PMD_SHIFT); + printk(KERN_INFO"PAGE_SHIFT = %d\n",PAGE_SHIFT); + + printk(KERN_INFO"PTRS_PER_PGD = %d\n",PTRS_PER_PGD); + printk(KERN_INFO"PTRS_PER_PUD = %d\n",PTRS_PER_PUD); + printk(KERN_INFO"PTRS_PER_PMD = %d\n",PTRS_PER_PMD); + printk(KERN_INFO"PTRS_PER_PTE = %d\n",PTRS_PER_PTE); + + printk(KERN_INFO"PAGE_MASK = 0x%lx\n",PAGE_MASK); + + if(!(pcb_tmp = find_task_by_pid(pid))) { + printk(KERN_INFO"Can't find the task %d .\n",pid); + return 0; + } + printk(KERN_INFO"pgd = 0x%p\n",pcb_tmp->mm->pgd); + /* 鍒ゆ柇缁欏嚭鐨勫湴鍧va鏄惁鍚堟硶(va<vm_end)*/ + if(!find_vma(pcb_tmp->mm,va)){ + printk(KERN_INFO"virt_addr 0x%lx not available.\n",va); + return 0; + } + pgd_tmp = pgd_offset(pcb_tmp->mm,va); + printk(KERN_INFO"pgd_tmp = 0x%p\n",pgd_tmp); + printk(KERN_INFO"pgd_val(*pgd_tmp) = 0x%lx\n",pgd_val(*pgd_tmp)); + if(pgd_none(*pgd_tmp)){ + printk(KERN_INFO"Not mapped in pgd.\n"); + return 0; + } + pud_tmp = pud_offset(pgd_tmp,va); + printk(KERN_INFO"pud_tmp = 0x%p\n",pud_tmp); + printk(KERN_INFO"pud_val(*pud_tmp) = 0x%lx\n",pud_val(*pud_tmp)); + if(pud_none(*pud_tmp)){ + printk(KERN_INFO"Not mapped in pud.\n"); + return 0; + } + pmd_tmp = pmd_offset(pud_tmp,va); + printk(KERN_INFO"pmd_tmp = 0x%p\n",pmd_tmp); + printk(KERN_INFO"pmd_val(*pmd_tmp) = 0x%lx\n",pmd_val(*pmd_tmp)); + if(pmd_none(*pmd_tmp)){ + printk(KERN_INFO"Not mapped in pmd.\n"); + return 0; + } + /*鍦ㄨ繖閲岋紝鎶婂師鏉ョ殑pte_offset_map()鏀规垚浜唒te_offset_kernel*/ + pte_tmp = pte_offset_kernel(pmd_tmp,va); + + printk(KERN_INFO"pte_tmp = 0x%p\n",pte_tmp); + printk(KERN_INFO"pte_val(*pte_tmp) = 0x%lx\n",pte_val(*pte_tmp)); + if(pte_none(*pte_tmp)){ + printk(KERN_INFO"Not mapped in pte.\n"); + return 0; + } + if(!pte_present(*pte_tmp)){ + printk(KERN_INFO"pte not in RAM.\n"); + return 0; + } + pa = (pte_val(*pte_tmp) & PAGE_MASK) |(va & ~PAGE_MASK); + printk(KERN_INFO"virt_addr 0x%lx in RAM is 0x%lx .\n",va,pa); + printk(KERN_INFO"contect in 0x%lx is 0x%lx\n",pa, + *(unsigned long *)((char *)pa + PAGE_OFFSET)); + + return 0; + +} + +static void find_pgd_exit(void) +{ + printk(KERN_INFO"Goodbye!\n"); + +} + +module_init(find_pgd_init); +module_exit(find_pgd_exit); diff --git a/study/engine/pid/Makefile b/study/engine/pid/Makefile new file mode 100644 index 0000000..2d9e86f --- /dev/null +++ b/study/engine/pid/Makefile @@ -0,0 +1,11 @@ +obj-m := list.o + +KERNELDIR ?= /lib/modules/$(shell uname -r)/build + +PWD := $(shell pwd) + +all: + make -C $(KERNELDIR) M=$(PWD) modules + +clean: + make -C $(KERNELDIR) M=$(PWD) clean diff --git a/study/engine/pid/pid.c b/study/engine/pid/pid.c new file mode 100644 index 0000000..4831102 --- /dev/null +++ b/study/engine/pid/pid.c @@ -0,0 +1,111 @@ +銆銆#include + +銆銆#include + +銆銆#include + +銆銆#include + +銆銆#define METHOD 2 + +銆銆static int list_init(void) + +銆銆{ + + 銆銆struct task_struct *task, *p; + + 銆銆struct list_head *pos; + + 銆銆int count; + + 銆銆char *method; + + 銆銆count = 0; /*涓嬮潰杩欎簺鍒濆鍖栧畬鍏ㄦ槸涓轰簡娑堥櫎缂栬瘧鏃剁殑璀﹀憡淇℃伅*/ + + 銆銆p = NULL; + + 銆銆task = NULL; + + 銆銆pos = NULL; + + 銆銆method = NULL; + + 銆銆task = &init_task; + + 銆銆printk(KERN_ALERT"PID/tCOMM/n"); + + 銆銆switch(METHOD) { + + 銆銆case 1: + + 銆銆method="list_for_each"; + + 銆銆break; + + 銆銆case 2: + + 銆銆method="for_each_process"; + + 銆銆break; + + 銆銆case 3: + + 銆銆method="list_for_each_entry"; + + 銆銆break; + + 銆銆} + + 銆銆printk( "The method is %s/n", method ); + +#if METHOD == 1 + + 銆銆list_for_each( pos, &task->tasks ) { + + 銆銆p = list_entry( pos, struct task_struct, tasks ); + + 銆銆count++; + + 銆銆printk( KERN_ALERT "%d/t%s/n", p->pid, p->comm ); + + 銆銆} + +#elif METHOD == 2 + + 銆銆for_each_process(task) { + + 銆銆count++; + + 銆銆printk( KERN_ALERT "%d/t%s/n", task->pid, task->comm ); + + 銆銆} + +#elif METHOD == 3 + + 銆銆 list_for_each_entry( p, &task->tasks, tasks ) { + + 銆銆 count++; + + printk( KERN_ALERT "%d/t%s/n", p->pid, p->comm ); + } + +#endif + + 銆printk("绯荤粺褰撳墠鍏 %d 涓繘绋!!", count); + + return 0; + +} + +static void list_exit(void) +{ + printk( KERN_ALERT "GOOD BYE!!/n"); +} + +module_init( list_init ); + +module_exit( list_exit ); + +MODULE_AUTHOR( "Along" ); + +MODULE_LICENSE( "GPL" ); diff --git a/study/memdev/Makefile b/study/memdev/Makefile new file mode 100644 index 0000000..e4a57d4 --- /dev/null +++ b/study/memdev/Makefile @@ -0,0 +1,14 @@ + + +obj-m := mem_dev.o + +KERNELDIR ?= /lib/modules/$(shell uname -r)/build + +PWD := $(shell pwd) + +all: + make -C $(KERNELDIR) M=$(PWD) modules + +clean: + make -C $(KERNELDIR) M=$(PWD) clean + diff --git a/study/memdev/devkmem.c b/study/memdev/devkmem.c new file mode 100644 index 0000000..3ee4863 --- /dev/null +++ b/study/memdev/devkmem.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEVKMEM "/dev/kmem" + +#define PAGE_SIZE 0x1000 +#define PAGE_MASK (~(PAGE_SIZE-1)) + + +int main(int argc, char* argv[]) +{ + if(argc != 2) + { + printf("usage..."); + exit(-1); + } + int fd; + char *mbase; + char read_buf[10]; + unsigned int regAddr; + unsigned int varAddr; + + varAddr = strtoul(argv[1], 0, 16); + + unsigned int ptr = varAddr & ~(PAGE_MASK); + + fd = open(DEVKMEM, O_RDONLY); + if (fd == -1) + { + printf("%s %d", __func__, __LINE__); + perror("open"); + exit(-1); + } + + mbase = (char *)mmap(0, PAGE_SIZE, PROT_READ, MAP_SHARED,fd, (varAddr & PAGE_MASK)); + if (mbase == MAP_FAILED) + { + printf("map failed %s\n",strerror(errno)); + } + + printf("varAddr = 0x%X \n", varAddr); + printf("mapbase = 0x%X \n", (unsigned int)mbase); + printf("value = 0x%X \n",*(unsigned int*)(mbase+ptr)); + printf("char = %c%c%c%c \n", + *(char *)(mbase+ptr), *(char *)(mbase+ptr+1), + *(char *)(mbase+ptr+2), *(char *)(mbase+ptr+3)); + + close(fd); + munmap(mbase,PAGE_SIZE); + + return 0; +} diff --git a/study/memdev/devmem.c b/study/memdev/devmem.c new file mode 100644 index 0000000..70f30a4 --- /dev/null +++ b/study/memdev/devmem.c @@ -0,0 +1,132 @@ +/* + * devmem2.c: Simple program to read/write from/to any location in memory. + * + * Copyright (C) 2000, Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl) + * + * + * This software has been developed for the LART computing board + * (http://www.lart.tudelft.nl/). The development has been sponsored by + * the Mobile MultiMedia Communications (http://www.mmc.tudelft.nl/) + * and Ubiquitous Communications (http://www.ubicom.tudelft.nl/) + * projects. + * + * The author can be reached at: + * + * Jan-Derk Bakker + * Information and Communication Theory Group + * Faculty of Information Technology and Systems + * Delft University of Technology + * P.O. Box 5031 + * 2600 GA Delft + * The Netherlands + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \ + __LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0) + +#define MAP_SIZE 4096UL +#define MAP_MASK (MAP_SIZE - 1) + +int main(int argc, char **argv) { + int fd; + void *map_base, *virt_addr; + unsigned long read_result, writeval; + off_t target; + int access_type = 'w'; + + if(argc < 2) { + fprintf(stderr, "\nUsage:\t%s { address } [ type [ data ] ]\n" + "\taddress : memory address to act upon\n" + "\ttype : access operation type : [b]yte, [h]alfword, [w]ord\n" + "\tdata : data to be written\n\n", + argv[0]); + exit(1); + } + target = strtoul(argv[1], 0, 0); + + if(argc > 2) + access_type = tolower(argv[2][0]); + + + if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL; + printf("/dev/mem opened.\n"); + fflush(stdout); + + /* Map one page */ + map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target & ~MAP_MASK); + if(map_base == (void *) -1) FATAL; + printf("Memory mapped at address %p.\n", map_base); + fflush(stdout); + + virt_addr = map_base + (target & MAP_MASK); + switch(access_type) { + case 'b': + read_result = *((unsigned char *) virt_addr); + break; + case 'h': + read_result = *((unsigned short *) virt_addr); + break; + case 'w': + read_result = *((unsigned long *) virt_addr); + break; + default: + fprintf(stderr, "Illegal data type '%c'.\n", access_type); + exit(2); + } + printf("Value at address 0x%X (%p): 0x%X\n", target, virt_addr, read_result); + fflush(stdout); + + if(argc > 3) + { + writeval = strtoul(argv[3], 0, 0); + switch(access_type) { + case 'b': + *((unsigned char *) virt_addr) = writeval; + read_result = *((unsigned char *) virt_addr); + break; + case 'h': + *((unsigned short *) virt_addr) = writeval; + read_result = *((unsigned short *) virt_addr); + break; + case 'w': + *((unsigned long *) virt_addr) = writeval; + read_result = *((unsigned long *) virt_addr); + break; + } + printf("Written 0x%X; readback 0x%X\n", writeval, read_result); + fflush(stdout); + } + + if(munmap(map_base, MAP_SIZE) == -1) FATAL; + close(fd); + return 0; +} + diff --git a/study/memdev/getjiff.c b/study/memdev/getjiff.c new file mode 100644 index 0000000..d13bd57 --- /dev/null +++ b/study/memdev/getjiff.c @@ -0,0 +1,140 @@ + +/* +* getjiff.c +* +* this toolkit shows how to get jiffies value from user space: +* 1. find jiffies's address from kernel image. +* 2. access virtual address space to get jiffies value. +* 3. access physical address sapce to get jiffies value. +* +* demostrate following techniques: +* o get ELF object symbol address by calling nlist() +* o access virtual memory space from /dev/kmem +* o access virtual memory space from /dev/mem +*/ + +#include +#include //exit +#include //nlist +#include +#include +#include +#include +#include +#include +#include +#include + +#define LONG *(volatile unsigned long*) + +/* read from virtual memory */ +int read_kmem(off_t offset, void* buf, size_t count) +{ + int fd; + int n; + + fd = open("/dev/kmem", O_RDONLY); + if (fd < 0) + { + perror("open /dev/kmem failed"); + return -1; + } + + lseek(fd, offset, SEEK_SET); + n = read(fd, buf, count); + if (n != count) + perror("/dev/kmem read failed"); + else + printf("/dev/kmem read buf = %ld\n", *(unsigned long *)buf); + + close(fd); + return n; +} + +/* read from physical memory */ +int read_mem(off_t offset, void* buf, size_t count) +{ + int fd; + int n; + int page_size; + void *map_base; + unsigned long value; + + printf("/dev/mem: the offset is %lx\n", offset); + + fd = open("/dev/mem", O_RDONLY); + if (fd < 0) + { + perror("open /dev/mem failed"); + return -1; + } + + if(1){ + page_size = getpagesize(); + printf("the page size = %d\n", page_size); + map_base = mmap(0,page_size,PROT_READ,MAP_SHARED,fd,offset); + if (map_base == MAP_FAILED){ + perror("mmap"); + exit(1); + } + value = LONG(map_base); + printf("/dev/mem: the value is %ld\n", value); + buf = (unsigned long *)map_base; + } + + if(0){ + lseek(fd, offset, SEEK_SET); + n = read(fd, buf, count); + if (n != count) + perror("/dev/mem read failed"); + else + printf("/dev/mem read buf = %ld\n", *(unsigned long *)buf); + } + + close(fd); + return n; +} + +int main(int argc, char **argv) +{ + FILE *fp; + char addr_str[11]="0x"; + char var[51]; + unsigned long addr; + unsigned long jiffies; + char ch; + int r; + + if (argc != 2) { + fprintf(stderr,"usage: %s System.map\n",argv[0]); + exit(-1); + } + + if ((fp = fopen(argv[1],"r")) == NULL) { + perror("fopen"); + exit(-1); + } + + do { + r = fscanf(fp,"%8s %c %50s\n",&addr_str[2],&ch,var); // format of System.map + if (strcmp(var,"jiffies")==0) + break; + } while(r > 0); + if (r < 0) { + printf("could not find jiffies\n"); + exit(-1); + } + + addr = strtoul(addr_str,NULL,16); //Convert string to unsigned long integer + printf("found jiffies at (%s) %08lx\n",addr_str,addr); + + read_kmem(addr, &jiffies, sizeof(jiffies)); + printf("jiffies=%ld (read from virtual memory)\n\n", jiffies); + + jiffies = 0; //reinit for checking read_mem() below + + read_mem(addr-0xC0000000, &jiffies, sizeof(jiffies)); + printf("jiffies=%ld (read from physical memory)\n", jiffies); + + return 0; +} diff --git a/study/memdev/mem_dev.c b/study/memdev/mem_dev.c new file mode 100644 index 0000000..dac4132 --- /dev/null +++ b/study/memdev/mem_dev.c @@ -0,0 +1,73 @@ +/************************************************************************* + > File Name: process.c + > Author: GatieMe + > Mail: gatieme@163.com + > Created Time: 2016骞04鏈01鏃 鏄熸湡浜 21鏃09鍒29绉 + ************************************************************************/ + + + +#include +#include +#include + +#include + + + +//#define METHOD 2 +static unsigned int METHOD = 1; +module_param(METHOD, uint,0400); + +long readPhysicsAddress(unsigned long pa, int *pStatus); + +long writePhysicsAddress(unsigned long pa, unsigned long data, int *pStatus); + + + +static int mem_dev_init(void) +{ + + readPhysicsAddress(0x12345, NULL); + return 0; +} + +static void mem_dev_exit(void) +{ + printk( KERN_ALERT "GOOD BYE!!\n"); +} + + + +/** add by gatieme */ +/* + * + */ +long readPhysicsAddress(unsigned long pa, int *pStatus) +{ + long data = -1; + //long *point = (long *)pa; + data = *(long *)pa; + printk(KERN_INFO "physics address : 0x%lx, data : 0x%lx", pa, data); + + return data; +} + +long writePhysicsAddress(unsigned long pa, unsigned long data, int *pStatus) +{ + long oldData = -1; + + oldData = *(long *)pa; + printk(KERN_INFO "physics address : 0x%lx, old data : 0x%lx", pa, *(long *)pa); + + *(long *)pa = data; + printk(KERN_INFO "physics address : 0x%lx, new data : 0x%lx", pa, *(long *)pa); + + return oldData; +} + +module_init(mem_dev_init); +module_exit(mem_dev_exit); + +MODULE_AUTHOR("gatieme"); +MODULE_LICENSE("GPL");