Skip to content

Commit 234d1f7

Browse files
自动修补函数偏移
1 parent 6184331 commit 234d1f7

File tree

4 files changed

+53
-27
lines changed

4 files changed

+53
-27
lines changed

README.md

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313

1414
**set_fun_info**函数用于在so文件的指定偏移处设置uprobe挂载点,并可传递指定函数名。
1515

16-
**set_fun_info2**函数用于在set_fun_info函数设置成功但失效的情况下,与set_fun_info函数作用一致。
17-
1816
**clear_all_uprobes**函数用于清除所有的uprobe挂载点。
1917

2018
上述函数的返回结果有SET_TRACE_SUCCESS、SET_TRACE_ERROR两种,分别表示设置成功和失败。
@@ -26,8 +24,5 @@
2624
目前只在5.10以及5.15两个版本通过测试,理论上5.10以上版本都能正常使用。
2725

2826
# 一些疑惑
29-
set_fun_info2函数其实就是将传入的函数偏移-0x1000再传递到内核,为什么要这样做?其实是因为
30-
在内核使用uprobe_register函数注册uprobe挂载点的时候在一些情况下会出现实际注册的函数偏移比
31-
传入的偏移多上0x1000,而如果我们传入的偏移-0x1000就正好抵消了这个影响。至于为什么会这样,
32-
我翻阅linux内核源码发现问题出现于[内存地址计算错误](https://elixir.bootlin.com/linux/v5.15.74/source/kernel/events/uprobes.c#L1004),从这里开始内存地址就多加上了0x1000,我推测是内存页少算了
33-
一页,但是具体原因不清楚。
27+
在内核使用uprobe_register函数注册uprobe挂载点的时候在一些特殊情况下会出现实际注册的函数偏移与传入的函数偏移不一致的问题,至于为什么会这样,
28+
我翻阅linux内核源码发现问题出现于[内存地址计算错误](https://elixir.bootlin.com/linux/v5.15.74/source/kernel/events/uprobes.c#L1004),从这里开始内存地址就出现了偏差,我推测是内存页计算有偏差,但是具体原因不清楚。

kernel_trace.c

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@
1111
#include <syscall.h>
1212
#include <asm/current.h>
1313
#include <hook.h>
14+
#include <linux/err.h>
1415
#include "kernel_trace.h"
1516

1617
KPM_NAME("kernel_trace");
17-
KPM_VERSION("2.2.0");
18+
KPM_VERSION("3.0.0");
1819
KPM_LICENSE("GPL v2");
1920
KPM_AUTHOR("Test");
2021
KPM_DESCRIPTION("use uprobe trace some fun in kpm");
@@ -29,26 +30,27 @@ void (*rcu_read_unlock)(void) = 0;
2930
int (*trace_printk)(unsigned long ip, const char *fmt, ...) = 0;
3031

3132
void *show_map_vma_addr;
33+
void *build_map_info_addr;
3234

3335

3436
char file_name[MAX_PATH_LEN];
3537
uid_t target_uid = -1;
3638
unsigned long fun_offsets[MAX_HOOK_NUM];
39+
unsigned long test_fun_addr;
3740
int hook_num = 0;
3841
struct rb_root fun_info_tree = RB_ROOT;
3942
static struct inode *inode;
4043
unsigned long module_base = 0;
4144
static struct uprobe_consumer trace_uc;
45+
static long long addr_fixer = 0;
4246

4347

4448

4549
void before_show_map_vma(hook_fargs2_t *args, void *udata)
4650
{
47-
struct seq_file* o_seq_file;
4851
struct vm_area_struct *ovma;
4952
unsigned long start, end;
5053

51-
o_seq_file = (struct seq_file*)args->arg0;
5254
ovma = (struct vm_area_struct*)args->arg1;
5355
start = ovma->vm_start;
5456
end = ovma->vm_end;
@@ -58,6 +60,21 @@ void before_show_map_vma(hook_fargs2_t *args, void *udata)
5860
}
5961
}
6062

63+
void after_build_map_info(hook_fargs3_t *args, void *udata)
64+
{
65+
struct map_info *tret = (struct map_info *)args->ret;
66+
bool is_register = (bool)args->arg2;
67+
unsigned long tvaddr = tret->vaddr;
68+
long long fun_offset = (long long)args->arg1;
69+
70+
if(addr_fixer==0 && tvaddr!=test_fun_addr){
71+
addr_fixer = test_fun_addr < tvaddr ? (-(tvaddr-test_fun_addr)) : (test_fun_addr-tvaddr);
72+
logkd("+Test-Log+ addr_fixer:%lld\n",addr_fixer);
73+
args->ret = ERR_PTR(-TRACE_FLAG);
74+
return;
75+
}
76+
}
77+
6178
void before_mincore(hook_fargs3_t *args, void *udata){
6279
int trace_flag = (int)syscall_argn(args, 1);
6380
if(trace_flag<TRACE_FLAG || trace_flag>TRACE_FLAG+CLEAR_UPROBE){
@@ -86,7 +103,15 @@ void before_mincore(hook_fargs3_t *args, void *udata){
86103
goto error_out;
87104
}
88105
// logkd("+Test-Log+ fun_name:%s,fun_offset:0x%llx\n",fun_name,fun_offset);
89-
int hret = uprobe_register(inode,fun_offset,&trace_uc);
106+
if(addr_fixer==0){
107+
test_fun_addr = module_base+fun_offset;
108+
}
109+
int hret = uprobe_register(inode,fun_offset+addr_fixer,&trace_uc);
110+
111+
if(hret==-TRACE_FLAG){
112+
hret = uprobe_register(inode,fun_offset+addr_fixer,&trace_uc);
113+
}
114+
90115
if(hret<0){
91116
logke("+Test-Log+ set uprobe error in 0x%llx\n",fun_offset);
92117
goto error_out;
@@ -100,12 +125,14 @@ void before_mincore(hook_fargs3_t *args, void *udata){
100125
if(trace_info==SET_MODULE_BASE){
101126
module_base = (unsigned long)syscall_argn(args, 0);
102127
logkd("+Test-Log+ set module_base:0x%llx\n",module_base);
128+
addr_fixer = 0;
103129
goto success_out;
104130
}
105131

106132
if(trace_info==SET_TARGET_UID){
107133
target_uid = (uid_t)syscall_argn(args, 0);
108134
logkd("+Test-Log+ set target_uid:%d\n",target_uid);
135+
addr_fixer = 0;
109136
goto success_out;
110137
}
111138

@@ -122,17 +149,19 @@ void before_mincore(hook_fargs3_t *args, void *udata){
122149
inode = igrab(path.dentry->d_inode);
123150
path_put(&path);
124151
logkd("+Test-Log+ success set file inode\n");
152+
addr_fixer = 0;
125153
goto success_out;
126154
}
127155

128156
if(trace_info==CLEAR_UPROBE){
129157
rcu_read_unlock();//解锁,不然内核会崩
130158
for (int i = 0; i < hook_num; ++i) {
131-
uprobe_unregister(inode,fun_offsets[i],&trace_uc);
159+
uprobe_unregister(inode,fun_offsets[i]+addr_fixer,&trace_uc);
132160
}
133161
hook_num = 0;
134162
destroy_entire_tree(&fun_info_tree);
135163
logkd("+Test-Log+ success clear all uprobes\n");
164+
addr_fixer = 0;
136165
goto success_out;
137166
}
138167

@@ -157,13 +186,8 @@ static int trace_handler(struct uprobe_consumer *self, struct mpt_regs *regs){
157186
if(uid==target_uid){
158187
fun_offset = regs->pc-module_base;
159188
tfun = search_key_value(&fun_info_tree,fun_offset);
160-
if(tfun){
189+
if(likely(tfun)){
161190
goto target_out;
162-
}else{
163-
tfun = search_key_value(&fun_info_tree,fun_offset- 0x1000);
164-
if(likely(tfun)){
165-
goto target_out;
166-
}
167191
}
168192
}else{
169193
goto no_target_out;
@@ -203,6 +227,7 @@ static long kernel_trace_init(const char *args, const char *event, void *__user
203227
trace_printk = (typeof(trace_printk))kallsyms_lookup_name("__trace_printk");
204228

205229
show_map_vma_addr = (void *)kallsyms_lookup_name("show_map_vma");
230+
build_map_info_addr = (void *)kallsyms_lookup_name("build_map_info");
206231

207232
logkd("+Test-Log+ mtask_pid_nr_ns:%llx\n",mtask_pid_nr_ns);
208233
logkd("+Test-Log+ uprobe_register:%llx\n",uprobe_register);
@@ -221,11 +246,12 @@ static long kernel_trace_init(const char *args, const char *event, void *__user
221246
logkd("+Test-Log+ trace_printk:%llx\n",trace_printk);
222247

223248
logkd("+Test-Log+ show_map_vma_addr:%llx\n",show_map_vma_addr);
249+
logkd("+Test-Log+ build_map_info_addr:%llx\n",build_map_info_addr);
224250

225251
if(!(mtask_pid_nr_ns && uprobe_register && uprobe_unregister
226252
&& kern_path && igrab && path_put && rcu_read_unlock
227253
&& rb_erase && rb_insert_color && rb_first && trace_printk
228-
&& show_map_vma_addr)){
254+
&& show_map_vma_addr && build_map_info_addr)){
229255
logke("+Test-Log+ can not find some fun addr\n");
230256
return -1;
231257
}
@@ -244,6 +270,11 @@ static long kernel_trace_init(const char *args, const char *event, void *__user
244270
return -1;
245271
}
246272

273+
err = hook_wrap2(build_map_info_addr,NULL,after_build_map_info,0);
274+
if(err){
275+
logke("+Test-Log+ hook build_map_info error\n");
276+
return -1;
277+
}
247278

248279
logkd("+Test-Log+ success init\n");
249280
return 0;
@@ -260,9 +291,10 @@ static long kernel_trace_exit(void *__user reserved)
260291
{
261292
inline_unhook_syscall(__NR_mincore, before_mincore, 0);
262293
unhook(show_map_vma_addr);
294+
unhook(build_map_info_addr);
263295
rcu_read_unlock();//解锁,不然内核会崩
264296
for (int i = 0; i < hook_num; ++i) {
265-
uprobe_unregister(inode,fun_offsets[i],&trace_uc);
297+
uprobe_unregister(inode,fun_offsets[i]+addr_fixer,&trace_uc);
266298
}
267299
logkd("+Test-Log+ success clear all uprobes\n");
268300
destroy_entire_tree(&fun_info_tree);

kernel_trace.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,10 @@ struct vm_area_struct {
8181
unsigned long vm_end;
8282
};
8383

84+
struct map_info {
85+
struct map_info *next;
86+
struct mm_struct *mm;
87+
unsigned long vaddr;
88+
};
89+
8490
struct pid_namespace;

user/uprobe_trace_user.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,6 @@ int set_fun_info(unsigned long fun_offset,char *fun_name){
3737
return ret;
3838
}
3939

40-
//set_fun_info函数设置成功但失效的情况下再用这个函数
41-
//,最好在一个程序内不要与set_fun_info函数同时使用
42-
int set_fun_info2(unsigned long fun_offset,char *fun_name){
43-
int ret = syscall(__NR_mincore,fun_offset-0x1000,TRACE_FLAG+SET_FUN_INFO,fun_name);
44-
return ret;
45-
}
46-
4740
int clear_all_uprobes(){
4841
int ret = syscall(__NR_mincore,0,TRACE_FLAG+CLEAR_UPROBE,"");
4942
return ret;

0 commit comments

Comments
 (0)