2017-04-04 94 views
0

我正在編寫一個LKM來查看文件的擴展屬性,以確定它是否應該打開。我有一個insmode:模塊問題中的未知符號。我無法找到造成這種情況的原因。模塊下:Insmod:模塊問題中的未知符號

#include <linux/module.h> /* Needed by all kernel modules */ 
#include <linux/kernel.h> /* Needed for loglevels (KERN_WARNING, KERN_EMERG, KERN_INFO, etc.) */ 
#include <linux/init.h> /* Needed for __init and __exit macros. */ 
#include <linux/unistd.h> /* sys_call_table __NR_* system call function indices */ 
#include <linux/fs.h>  /* filp_open */ 
#include <linux/slab.h> /* kmalloc */ 
#include <asm/paravirt.h> /* write_cr0 */ 
#include <asm/uaccess.h> /* get_fs, set_fs */ 
#include <linux/xattr.h> 
#include <linux/dcache.h> /*dentry*/ 


#define PROC_V "/proc/version" 
#define BOOT_PATH "/boot/System.map-" 
#define MAX_VERSION_LEN 256 


//https://tnichols.org/2015/10/19/Hooking-the-Linux-System-Call-Table/ 



unsigned long *syscall_table = NULL; 
//unsigned long *syscall_table = (unsigned long *)0xffffffff81801400; 
asmlinkage int (*original_open)(const char*, int flags, mode_t); 
static int find_sys_call_table (char *kern_ver) { 
    char system_map_entry[MAX_VERSION_LEN]; 
    int i = 0; 
    /* 
    * Holds the /boot/System.map-<version> file name as we build it 
    */ 
    char *filename; 
    /* 
    * Length of the System.map filename, terminating NULL included 
    */ 
    size_t filename_length = strlen(kern_ver) + strlen(BOOT_PATH) + 1; 
    /* 
    * This will point to our /boot/System.map-<version> file 
    */ 
    struct file *f = NULL; 

    mm_segment_t oldfs; 

    oldfs = get_fs(); 
    set_fs (KERNEL_DS); 
    printk(KERN_EMERG "Kernel version: %s\n", kern_ver); 

    filename = kmalloc(filename_length, GFP_KERNEL); 
    if (filename == NULL) { 
     printk(KERN_EMERG "kmalloc failed on System.map-<version> filename allocation"); 
     return -1; 
    } 

    /* 
    * Zero out memory to be safe 
    */ 
    memset(filename, 0, filename_length); 

    /* 
    * Construct our /boot/System.map-<version> file name 
    */ 
    strncpy(filename, BOOT_PATH, strlen(BOOT_PATH)); 
    strncat(filename, kern_ver, strlen(kern_ver)); 

    /* 
    * Open the System.map file for reading 
    */ 
    f = filp_open(filename, O_RDONLY, 0); 
    if (IS_ERR(f) || (f == NULL)) { 
     printk(KERN_EMERG "Error opening System.map-<version> file: %s\n", filename); 
     return -1; 
    } 

    memset(system_map_entry, 0, MAX_VERSION_LEN); 

    /* 
    * Read one byte at a time from the file until we either max out 
    * out our buffer or read an entire line. 
    */ 
    while (vfs_read(f, system_map_entry + i, 1, &f->f_pos) == 1) { 
     /* 
     * If we've read an entire line or maxed out our buffer, 
     * check to see if we've just read the sys_call_table entry. 
     */ 
     if (system_map_entry[i] == '\n' || i == MAX_VERSION_LEN) { 
      // Reset the "column"/"character" counter for the row 
      i = 0; 

      if (strstr(system_map_entry, "sys_call_table") != NULL) { 
       char *sys_string; 
       char *system_map_entry_ptr = system_map_entry; 

       sys_string = kmalloc(MAX_VERSION_LEN, GFP_KERNEL); 
       if (sys_string == NULL) { 
        filp_close(f, 0); 
        set_fs(oldfs); 
        kfree(filename); 

        return -1; 
       } 

       memset(sys_string, 0, MAX_VERSION_LEN); 
       strncpy(sys_string, strsep(&system_map_entry_ptr, " "), MAX_VERSION_LEN); 

       //syscall_table = (unsigned long long *) kstrtoll(sys_string, NULL, 16); 
       //syscall_table = kmalloc(sizeof(unsigned long *), GFP_KERNEL); 
       //syscall_table = kmalloc(sizeof(syscall_table), GFP_KERNEL); 
       kstrtoul(sys_string, 16, &syscall_table); 
       printk(KERN_EMERG "syscall_table retrieved\n"); 

       kfree(sys_string); 

       break; 
      } 

      memset(system_map_entry, 0, MAX_VERSION_LEN); 
      continue; 
     } 

     i++; 
    } 

    filp_close(f, 0); 
    set_fs(oldfs); 

    kfree(filename); 

    return 0; 
} 
/* 
* We have to pass in a pointer to a buffer to store the parsed 
* version information in. If we declare a pointer to the 
* parsed version info on the stack of this function, the 
* pointer will disappear when the function ends and the 
* stack frame is removed. 
*/ 
char *acquire_kernel_version (char *buf) { 
    struct file *proc_version; 
    char *kernel_version; 

    /* 
    * We use this to store the userspace perspective of the filesystem 
    * so we can switch back to it after we are done reading the file 
    * into kernel memory 
    */ 
    mm_segment_t oldfs; 

    /* 
    * Standard trick for reading a file into kernel space 
    * This is very bad practice. We're only doing it here because 
    * we're malicious and don't give a damn about best practices. 
    */ 
    oldfs = get_fs(); 
    set_fs (KERNEL_DS); 

    /* 
    * Open the version file in the /proc virtual filesystem 
    */ 
    proc_version = filp_open(PROC_V, O_RDONLY, 0); 
    if (IS_ERR(proc_version) || (proc_version == NULL)) { 
     return NULL; 
    } 

    /* 
    * Zero out memory just to be safe 
    */ 
    memset(buf, 0, MAX_VERSION_LEN); 

    /* 
    * Read version info from /proc virtual filesystem 
    */ 
    vfs_read(proc_version, buf, MAX_VERSION_LEN, &(proc_version->f_pos)); 

    /* 
    * Extract the third field from the full version string 
    */ 
    kernel_version = strsep(&buf, " "); 
    kernel_version = strsep(&buf, " "); 
    kernel_version = strsep(&buf, " "); 

    filp_close(proc_version, 0); 

    /* 
    * Switch filesystem context back to user space mode 
    */ 
    set_fs(oldfs); 

    return kernel_version; 
} 
asmlinkage int new_open (const char* path, int flags, mode_t mode) { 
    //printk(KERN_EMERG "[+] open() hooked."); 

    char *start = "root/home/"; 

    if(strncmp(start,path,sizeof(char)*10)){ 

     mm_segment_t oldfs; 
     struct file *f; 
     int val; 
     struct dentry *dentry; 

     oldfs = get_fs(); 
     set_fs (KERNEL_DS); 
     f = filp_open(path, O_RDONLY, 0); 
     if(f){ 
      dentry = f->f_path.dentry; 
      filp_close(f, 0); 
      val = vfs_getxattr(dentry, "user.lock", NULL, 0); 
      //printk(KERN_EMERG "%d %s\n", val, path); 
      if(val != 0) return -1; 
     } 

     set_fs(oldfs); 
    } 
    return original_open(path, flags, mode); 
} 


static int __init onload(void) { 
    char *kernel_version = kmalloc(MAX_VERSION_LEN, GFP_KERNEL); 
    printk(KERN_WARNING "Hello world!\n"); 
    // printk(KERN_EMERG "Version: %s\n", acquire_kernel_version(kernel_version)); 

    find_sys_call_table(acquire_kernel_version(kernel_version)); 

    printk(KERN_EMERG "Syscall table address: %p\n", syscall_table); 
    printk(KERN_EMERG "sizeof(unsigned long *): %zx\n", sizeof(unsigned long*)); 
    printk(KERN_EMERG "sizeof(sys_call_table) : %zx\n", sizeof(syscall_table)); 

    if (syscall_table != NULL) { 
     write_cr0 (read_cr0() & (~ 0x10000)); 
     original_open = (void *)syscall_table[__NR_open]; 
     syscall_table[__NR_open] = &new_open; 
     write_cr0 (read_cr0() | 0x10000); 
     printk(KERN_EMERG "[+] onload: sys_call_table hooked\n"); 
    } else { 
     printk(KERN_EMERG "[-] onload: syscall_table is NULL\n"); 
    } 

    kfree(kernel_version); 

    /* 
    * A non 0 return means init_module failed; module can't be loaded. 
    */ 
    return 0; 
} 
static void __exit onunload(void) { 
    if (syscall_table != NULL) { 
     write_cr0 (read_cr0() & (~ 0x10000)); 
     syscall_table[__NR_open] = original_open; 
     write_cr0 (read_cr0() | 0x10000); 
     printk(KERN_EMERG "[+] onunload: sys_call_table unhooked\n"); 
    } else { 
     printk(KERN_EMERG "[-] onunload: syscall_table is NULL\n"); 
    } 
    printk(KERN_INFO "Goodbye world!\n"); 
} 
module_init(onload); 
module_exit(onunload); 

當我註釋掉val = vfs_getxattr(dentry, "user.lock", NULL, 0);(在new_open()),然後將其安裝。我無法弄清楚是什麼原因導致這個問題,任何想法都會被張開雙臂歡迎!

回答

2

符號vfs_getxattr僅出口僅適用於GPL模塊(與EXPORT_SYMBOL_GPL)。

你需要

MODULE_LICENSE("GPL"); 

您模塊中使用這樣的符號。


它始終是最好有MODULE_LICENSE();在每個驅動器,無論是「通用公共許可證」或專有的。

+0

謝謝!我注意到,在以前的版本中遺漏了,但忘了把它放在新的版本! –

+0

不幸的是我現在得到的錯誤: 「致命modpost:GLP不兼容模塊filebunker.ko使用GLP專用符號'vfs_getxattr'」 –

+1

您的意思是「GPL」而不是「GLP」?請檢查您是否使用了適當的許可證值。 – Tsyvarev