Jprobes

【用途】

类似于Kprobes和Return Probes,区别在于,Kprobes可以在任意指令处插入探针,Jprobes只在函数入口插入探针,而Return Probes则是在函数返回时插入探针。

【接口说明】【参考samples/kprobes/jprobe_example.c】

#include <linux/kprobes.h>

int register_jprobe(struct jprobe *jp);

void unregister_jprobe(struct jprobe *jp);

int enable_jprobe(struct jprobe *jp);

int disable_jprobe(struct jprobe *jp);

【番外篇】

我这篇也就写点儿使用Kprobe和Jprobe的注意事项:

用Kprobe和retprobe注册的handler运行于原子(atomic)上下文,因为它们都是运行在int3的异常处理函数或调试(debug)中断的处理函数中,并且两者都是在关闭当前cpu中断的前提下执行的。相比之下,Jprobe就灵活得多了,用它注册的handler的执行环境和原始的执行环境并没有两样,堆栈环境和cpu寄存器都是相同的。

因为Jprobe执行用户注册的handler之前有保存现场(主要是int3之前的CPU寄存器的值)的工作,所以Jprobe的handler是没有办法破坏寄存器的值的,但是可以改变堆栈中的变量的值,Kprobe将没有这些限制,它对系统具有完全的访问权限,另一方面,Kprobe也比Jprobe危险得多,如果只是简单的打印一些系统信息,推荐用Jprobe,不要冒险!

Jprobe机制和用户空间的setjmp和longjmp的实现比较类似,事实上,它的内核代码的注释部分也是如此作类比的,所以用register_jprobe注册的代码段,最后必须要用jprobe_return进行返回,当然,如果你想让它一去不复返除外。这点就象用kprobe注册的handler必须是可以返回的函数一样。目前,能想到的就这么多了。

BTW: 看kprobe的内核代码的时侯,发现有的地方还是有些缺陷的,比如说某些地方用preempt_disable()关闭了抢占,但是当函数出错返回的时侯,并没有打开抢占。不知道最新的内核有没有修复这些细节,懒得去看了,应该没有哪个正式的发型版会打开这个选项的。所以文章标题中所提到的注入的可能性也就比较小了,本来这个东西出现的背景就是为了方便内核开发者的调试工作!

【实例】

/*jprobe_test.c */

#include <linux/kernel.h>

#include <linux/module.h>

#include <linux/fs.h>

#include <linux/uio.h>

#include <linux/kprobes.h>

#include <linux/kallsyms.h>

/*

* Jumper probe for do_fork.

* Mirror principle enables access to arguments of the probed routine

* from the probe handler.

*/

/* Proxy routine having the same arguments as actual do_fork() routine */

long jdo_fork(

  unsigned long clone_flags,

  unsigned long stack_start,

struct pt_regs *regs,

  unsigned long stack_size,

  int __user * parent_tidptr,

  int __user * child_tidptr) {

  printk("jprobe: clone_flags=0x%lx, stack_size=0x%lx, regs=0x%p\n",       clone_flags, stack_size, regs);

  /* Always end with a call to jprobe_return(). */

  jprobe_return();

  /*NOTREACHED*/

  return 0;

}

static struct jprobe my_jprobe = {

.entry = (kprobe_opcode_t *) jdo_fork

};

int init_module(void) {

int ret;

my_jprobe.kp.addr = (kprobe_opcode_t *) kallsyms_lookup_name("do_fork");

if (!my_jprobe.kp.addr) {

printk("Couldn't find %s to plant jprobe\n", "do_fork");

return -1;

}

if ((ret = register_jprobe(&my_jprobe)) <0) {

printk("register_jprobe failed, returned %d\n", ret);

return -1;

}

printk("Planted jprobe at %p, handler addr %p\n",       my_jprobe.kp.addr, my_jprobe.entry);

return 0;

}

void cleanup_module(void) {   unregister_jprobe(&my_jprobe);   printk("jprobe unregistered\n"); }

MODULE_LICENSE("GPL");

最新文章

  1. JS创建对象篇
  2. jar包合并
  3. .NET Core 1.0-最简单的Hello world控制台程序
  4. py随笔
  5. 我是一只IT小小鸟
  6. PHP+memcache扩展(集成环境wampserver环境下)
  7. UEditor上传功能
  8. Git ~ 大杀器之一 远程仓库 ~ Git
  9. Difference between ref and out parameters
  10. &lt;二&gt; SQL 基础
  11. iOS 推送,当接到推送消息时如何处理?
  12. mahout分类
  13. java的几个版本以及jre,jdk等概念——【转载】JDK、Java SE、Java EE、Java ME我该选
  14. UVALive 6709 - Mosaic 二维线段树
  15. Linux下通过rm -f删除大量文件时提示&quot;-bash: /bin/rm: Argument list too long&quot;的解决方法
  16. JAVA语法基础(课堂ppt问题总结)
  17. nginx配置https双向验证(ca机构证书+自签证书)
  18. Python调用selenium
  19. 学习ActiveMQ(三):发布/订阅模式(topic)演示
  20. JavaScript 常用数组函数方法专题

热门文章

  1. vue 圆形进度条组件解析
  2. Django文档——Model中的ForeignKey,ManyToManyField与OneToOneField 关联关系字段 (Relationship fields)
  3. 小程序中页面兼容h5标签的解析
  4. C++实现简单的日志记录
  5. There are multiple modules with names that only differ in casing. This can lead to unexpected behavior when compiling on a filesystem with other case-semantic.
  6. 利用webSocket实现浏览器中多个标签页之间的通信
  7. pandas 常规操作大全
  8. Redis持久化rdb&amp;aof
  9. (架构)React Native 导出项目全局共用组件的模块
  10. python基础操作---string