Skip to content

Instantly share code, notes, and snippets.

@DavadDi
Created December 2, 2020 14:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DavadDi/a82f46a1bb9e9f5a6c22d44c8142e89b to your computer and use it in GitHub Desktop.
Save DavadDi/a82f46a1bb9e9f5a6c22d44c8142e89b to your computer and use it in GitHub Desktop.
// hijack.c
#include <linux/kernel.h> /* We're doing kernel work */
#include <linux/module.h> /* Specifically, a module */
#include <linux/proc_fs.h> /* Necessary because we use the proc fs */
#include <asm/uaccess.h> /* for copy_from_user */
#include <linux/fs.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/kallsyms.h>
#include <linux/cpu.h>
char *stub;
char *addr = NULL;
// 可以用JMP模式,也可以用CALL模式
//#define JMP 1
// 和 ipvs 模块里同名的 estimation_timer 函数
static void estimation_timer(unsigned long arg)
{
printk("estimation_timer patched\n");
return;
}
// hijack_stub的作用就类似于ftrace kpatch里的ftrace_regs_caller
static void hijack_stub(unsigned long arg)
{
// 用nop占位,加上C编译器自动生成的函数header代码,这么大的函数来容纳stub应该够了。
asm ("nop; nop; nop; nop; nop; nop; nop; nop;");
return;
}
#define FTRACE_SIZE 5
#define POKE_OFFSET 0
#define POKE_LENGTH 5
#define SKIP_LENGTH 8
static unsigned long *(*_mod_find_symname)(struct module *mod, const char *name);
static void *(*_text_poke_smp)(void *addr, const void *opcode, size_t len);
static struct mutex *_text_mutex;
unsigned char saved_inst[POKE_LENGTH];
struct module *mod;
static int __init hotfix_init(void)
{
unsigned char jmp_call[POKE_LENGTH];
unsigned char e8_skip_stack[SKIP_LENGTH];
s32 offset, i = 5;
mod = find_module("ip_vs");
printk("hotfix_init init\n");
if (!mod) {
printk("hotfix mod not found\n");
return -1;
}
_mod_find_symname = (void *)kallsyms_lookup_name("mod_find_symname");
if (!_mod_find_symname) {
printk("hotfix _mod_find_symname error");
return -1;
}
addr = (void *)_mod_find_symname(mod, "estimation_timer");
if (!addr) {
printk("hotfix addr estimation_timer NULL\n");
return -1;
}
printk("hotfix estimation_timer addr %p\n", addr);
_text_poke_smp = (void *)kallsyms_lookup_name("text_poke_smp");
_text_mutex = (void *)kallsyms_lookup_name("text_mutex");
if (!_text_poke_smp || !_text_mutex) {
printk("!_text_poke_smp || !_text_mutex");
return -1;
}
stub = (void *)hijack_stub;
offset = (s32)((long)estimation_timer - (long)stub - FTRACE_SIZE);
// 下面的代码就是stub函数的最终填充,它类似于ftrace_regs_caller的作用!
e8_skip_stack[0] = 0xe8;
(*(s32 *)(&e8_skip_stack[1])) = offset;
#ifndef JMP // 如果是call模式,则需要手工平衡堆栈,跳过原始函数的栈帧
e8_skip_stack[i++] = 0x41; // pop %r11
e8_skip_stack[i++] = 0x5b; // r11寄存器为临时使用寄存器,遵循调用者自行保护原则
#endif
e8_skip_stack[i++] = 0xc3;
_text_poke_smp(&stub[0], e8_skip_stack, SKIP_LENGTH);
offset = (s32)((long)stub - (long)addr - FTRACE_SIZE);
memcpy(&saved_inst[0], addr, POKE_LENGTH);
#ifndef JMP
jmp_call[0] = 0xe8;
#else
jmp_call[0] = 0xe9;
#endif
(*(s32 *)(&jmp_call[1])) = offset;
get_online_cpus();
mutex_lock(_text_mutex);
_text_poke_smp(&addr[POKE_OFFSET], jmp_call, POKE_LENGTH);
mutex_unlock(_text_mutex);
put_online_cpus();
printk("hotfix init return \n");
return 0;
}
static void __exit hotfix_exit(void)
{
printk("hotfix_exit enter\n");
mod = find_module("ip_vs");
if (!mod) {
printk("hotfix mod not found\n");
return;
}
addr = (void *)_mod_find_symname(mod, "estimation_timer");
if (!addr) {
printk("hotfix addr estimation_timer is NULL \n");
return;
}
printk("estimation_timer addr: %p\n", addr);
get_online_cpus();
mutex_lock(_text_mutex);
_text_poke_smp(&addr[POKE_OFFSET], &saved_inst[0], POKE_LENGTH);
mutex_unlock(_text_mutex);
put_online_cpus();
}
module_init(hotfix_init);
module_exit(hotfix_exit);
MODULE_LICENSE("GPL");
@DavadDi
Copy link
Author

DavadDi commented Dec 3, 2020

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment