openat(2) システムコールなどの LKM フックを使用した後、Linux がハングします。

openat(2) システムコールなどの LKM フックを使用した後、Linux がハングします。

私はシステムコール(たとえば)を接続することを目的として、学習目的で次のLKMを作成しましたopenat(2)

問題は、フックを正常に無効にしてCR0.WP設定した後にsys_call_table[__NR_openat]システムが停止することです。

Linuxカーネルについて深い知識を持っている人なら誰でもこのようなことが起こる理由についてコメントできますか?

ノート:

LKMを実行するにはCAP_SET_EMPTY_OFFSET、カーネルの対応するオフセットに置き換えるか、取得しSYS_CALL_TABLE_OFFSETたアドレスをハードコードする必要があります。sys_call_tablesudo cat /proc/kallsyms | grep sys_call_table

パスワード:

#include <linux/module.h>   /* Needed by all modules */
#include <linux/syscalls.h>
#include <linux/capability.h>
#include <linux/set_memory.h> /* Needed by set_memory_rw */

/*
 * Avoid tainting the kernel, however the kernel will still be tainted if the
 * module is not signed
 */
MODULE_LICENSE("GPL");

#define CAP_SET_EMPTY_OFFSET 0x45fe0
#define SYS_CALL_TABLE_OFFSET 0x2e0

static unsigned long* __sys_call_table;

unsigned long *find_sys_call_table(void)
{
   unsigned long rodata_start;
   rodata_start = (unsigned long)&__cap_empty_set - CAP_SET_EMPTY_OFFSET;
   return (unsigned long*)(rodata_start + SYS_CALL_TABLE_OFFSET);
}

static inline void __write_cr0(unsigned long val)
{
   asm volatile ("mov %0, %%cr0": : "r" (val));
}

static inline void disable_write_protection(void)
{
   preempt_disable();
   barrier();
   __write_cr0(read_cr0() & (~ 0x00010000));
}

static inline void enable_write_protection(void)
{
   __write_cr0(read_cr0() | 0x00010000);
   barrier();
   preempt_enable();
}
    
typedef asmlinkage long (*orig_openat_t)(int, const char*, int, umode_t);
orig_openat_t orig_openat;

asmlinkage long
hooked_openat(int dirfd, const char __user* pathname, int flags, umode_t mode)
{
   //printk(KERN_INFO "%s: hooked openat\n", __func__);
   return orig_openat(dirfd, pathname, flags, mode);
}


static int __init syscall_init(void)
{
   printk(KERN_DEBUG "%s: started\n", __func__);

   printk(KERN_INFO "%s: cr0: %lx\n", __func__, read_cr0());

   __sys_call_table = find_sys_call_table();
   printk(KERN_INFO "%s: __sys_call_table: %px\n", __func__, __sys_call_table);

   orig_openat = (orig_openat_t)__sys_call_table[__NR_openat];
   printk(KERN_INFO "%s: orig_openat: %px\n", __func__, (void*)orig_openat);

   disable_write_protection();
   printk(KERN_INFO "%s: cr0: %lx\n", __func__, read_cr0());

   __sys_call_table[__NR_openat] = (unsigned long)hooked_openat;
   printk(KERN_INFO "%s: hooked_openat: %px\n", __func__, (void*)hooked_openat);

   enable_write_protection();
   printk(KERN_INFO "%s: cr0: %lx\n", __func__, read_cr0());

   return 0;
}

static void __exit syscall_release(void)
{
   disable_write_protection();
   __sys_call_table[__NR_openat] = (unsigned long)orig_openat;
   enable_write_protection();

   printk(KERN_DEBUG "%s: exited\n", __func__);
}

/* set the entry point of the module */
module_init(syscall_init);
/* set the exit point of the module */
module_exit(syscall_release);

ベストアンサー1

orig_openat問題は、必要な場所に設定しないことです。

orig_openat = (orig_openat_t) _sys_call_table[__NR_openat];
_sys_call_table[__NR_openat] = (unsigned long)hooked_openat;

電話を切るとき。

おすすめ記事