首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

内核相关问题:kill init和内核结构的释放(2)

内核相关问题:kill init和内核结构的释放(2)

仅此而已,操作task_struct的字段了吗?没有,实际上 task_struct还是那个task_struct,一点没变,内核要想取该task_struct的某个字段,照取不误,还是原来的地址(内核的前 896m与物理内存一一对应),只是操作了slab的指针。因此进程依旧完好运行,那为何一旦ps就崩溃了呢?或者ls也崩溃。我们知道,你执行ps或 ls以及任何一个命令的时候,shell都要fork出一个新进程,而fork要分配一个task_struct,该task_struct当然在 slab分配,我们看看分配代码:
       
  • static inline void * __cache_alloc (kmem_cache_t *cachep, int flags)   
  • {   
  •          unsigned long save_flags;   

  • void* objp;   

  • struct array_cache *ac;   
  •          cache_alloc_debugcheck_before(cachep, flags);   
  •          local_irq_save(save_flags);   
  •          ac = ac_data(cachep);   

  • if (likely(ac->avail)) {   
  •                  STATS_INC_ALLOCHIT(cachep);   
  •                  ac->touched = 1;   
  •                  objp = ac_entry(ac)[--ac->avail];   
  •          } else {   
  •                  STATS_INC_ALLOCMISS(cachep);   
  •                  objp = cache_alloc_refill(cachep, flags);   
  •          }   
  •          local_irq_restore(save_flags);   
  •          objp = cache_alloc_debugcheck_after(cachep, flags, objp, __builtin_return_address(0));   

  • return objp;   
  • }

看看这个--ac->avail,再对 比一下前面释放时的ac->avail++,这里最新分配的task_struct就是最新被释放的task_struct,而这个 task_struct就是那个我的模块中被变态释放的task_struct了,于是新进程一产生,原来的被释放的进程的task_struct的所有 字段几乎都要被重置,如果我敲入了ps,那么那个while循环进程的task_struct将和ps的task_struct一样,因此乱套崩溃在情理 之中,为何乱套?最简单的例子,内核要调度while,切出while循环,但是他们的task_struct一样,如果你是内核你该咋办,绝对崩溃,要 你放下一个桔子拿起另一个桔子,而这两个桔子是一个桔子,你难道不崩溃吗?呵呵。
   因此,我认为因该在slab对象初始化时只初始化公共部分,只要释放一个slab对象到slab中,那么就把非公共部分清零,这样才安全,把一切清零,不 要什么工公共部分更安全,当然这样slab的ctor构造函数也就没有必要了,不过这样的效率会小低一些,仅仅小低一些。还是为了简单,我写下如下模块, 释放后随即将整个结构清零,不保留任何公共部分:
       
  • #include <linux/init.h>
       

  • #include <linux/module.h>
       

  • static __init int test_init(void)   
  • {   
  •     task_t *task=find_task_by_pid(1824);      
  •     free_task(task);   
  •     memset(task,0,sizeof(task_t));  //将task_struct清零,实际上就是将其内部的字段清零,包括指针变量,由此消除了野指针
       

  • return 0;   
  • }   

  • static __exit void test_exit(void)   
  • {   

  • return ;   
  • }   
  • module_init(test_init);   
  • module_exit(test_exit);   
  • MODULE_LICENSE("Dual BSD/GPL");   
  • MODULE_AUTHOR("Zhaoya");   
  • MODULE_DESCRIPTION("zero task");   
  • MODULE_VERSION("Ver 0.1");


还 是以上面的while循环作试验,加载模块后,内核立即崩溃,达到了目的。但是内核是怎么崩溃的呢?很简单,典型的有两个时机,一个是时钟中断,一个是调 度,当然还有别的很多,只是这两个更具有典型性,在这两个时机场景的处理时候会用到current,而它就是被释放那的task_struct,字段全是 0,这样很容易就崩溃了,可能访问了0指针也就是空指针,也可能是别的。在应用程序设计时,我们大谈特谈野指针的危害,内核中也要关注它,不过不必像用户 空间那么过分关注它,毕竟内核中做的事情应该形成一种约定,这样就不用浪费资源去验证这验证那了,内核做的事情要少而有效,最重要的是保证安全。
task_struct来自slab,而slab有ctor构造函数和dtor析构函数,dtor我们想想实际上是没有什么用的,于是在最新的内核中就去掉了,不再为slab对象提供析构函数了(参考slub)。
继承事业,薪火相传
返回列表