Linux x86内核终止D状态的进程
2016-11-07 21:25
363 查看
在《Linux如何终止D状态的进程》,我浮光掠影般描述了一种非规范的结束D进程的方法,只是一种方法,几乎没有可操作性。今天收到了一位朋友的邮件,问我exit_task1到底该怎么写。说实话,我本来不想把故事说完的,但是既然有人问了,我就再写两篇短文吧。本文介绍x86 32位系统中的详细方法,下一篇文章将介绍64位系统的方法。
我的exit_task1是以下这么写的:
事实上,以上写的对于大多数想拿来代码就编译运行的复制粘贴者而言,没有任何用处。到底该怎么办呢?我说过,要照着ret_from_fork做:
那么我也写个汇编文件func_.S:
完整的rmpid.c文件如下:
然后Makefile中把func_.S链进去即可:
obj-m += pidrm.o
pidrm-objs += rmpid.o func_.o
obj-m += bug4.o
编译完毕就可以演示了!在Makefile中,我顺带编译了一个bug4模块,它是一个有bug的模块,为了制造D进程:
#include <linux/module.h>
#include <linux/sched.h>
static int __init bug4_register(void)
{
struct module *o = THIS_MODULE;
// 递增一个永远都不会减的引用计数!
try_module_get(o);
return 0;
}
static void __exit
my_cleanup_module(void)
{
}
module_init(bug4_register);
module_exit(my_cleanup_module);
MODULE_AUTHOR("aaaa");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("bug");
一切编译工作都完成后,我们试着加载bug4.ko,然后运行:
rmmod --wait bug4
此时rmmod就变成D进程了!当我们以rmmod进程的pid为参数载入pidrm模块的时候,该rmmod进程将被杀死!
我的exit_task1是以下这么写的:
void exit_task1() { // 这个有点猛,仅为测试。 // emergency_restart(); // TODO:这里要做的事情非常多,类似ret_from_fork那样,要执行schedule_tail后处理之类的事情。 // 首先,你必须preempt_enable_no_resched,不然会锁死,其次,还要考虑schedule_tail的逻辑。 }
事实上,以上写的对于大多数想拿来代码就编译运行的复制粘贴者而言,没有任何用处。到底该怎么办呢?我说过,要照着ret_from_fork做:
ENTRY(ret_from_fork) CFI_STARTPROC pushl %eax CFI_ADJUST_CFA_OFFSET 4 call schedule_tail GET_THREAD_INFO(%ebp) popl %eax CFI_ADJUST_CFA_OFFSET -4 pushl $0x0202 # Reset kernel eflags CFI_ADJUST_CFA_OFFSET 4 popfl CFI_ADJUST_CFA_OFFSET -4 jmp syscall_exit CFI_ENDPROC END(ret_from_fork)
那么我也写个汇编文件func_.S:
#include <linux/linkage.h> #include <asm/thread_info.h> .global addr; addr: .fill 1,4,0 ENTRY(ret_from_disksleep) pushl %eax // call schedule_tail // schedule_tail没有导出,因此我只能从kallsyms里面找到0xc045d420这个地址。 call 0xc045d420 // 直接call函数地址 GET_THREAD_INFO(%ebp) popl %eax pushl $0x0202 # Reset kernel eflags popfl call do_exit // 调用exit,退出D进程 END(ret_from_disksleep)
完整的rmpid.c文件如下:
#include <linux/module.h> #include <linux/sched.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> static int pid __read_mostly = 0; module_param(pid, int, 0644); MODULE_PARM_DESC(pid, "pid"); static int address __read_mostly = 0; module_param(address, int, 0644); MODULE_PARM_DESC(address, "type"); extern unsigned long addr; asmlinkage void ret_from_disksleep(void) __asm__("ret_from_disksleep"); static int __init mymm_register(void) { struct task_struct *p; // TMD,在2.6.32中,kallsyms_lookup_name本身没有被导出!! //addr = kallsyms_lookup_name("schedule_tail"); addr = address; if (pid > 0) { for_each_process(p) { if (task_pid_vnr(p) == pid) { set_task_state(p, TASK_INTERRUPTIBLE); p->thread.ip = (unsigned long)ret_from_disksleep; wake_up_process(p); break; } } } out: return -ENOMEM; } module_init(mymm_register); MODULE_AUTHOR("aaaa"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("pid remove");
然后Makefile中把func_.S链进去即可:
obj-m += pidrm.o
pidrm-objs += rmpid.o func_.o
obj-m += bug4.o
编译完毕就可以演示了!在Makefile中,我顺带编译了一个bug4模块,它是一个有bug的模块,为了制造D进程:
#include <linux/module.h>
#include <linux/sched.h>
static int __init bug4_register(void)
{
struct module *o = THIS_MODULE;
// 递增一个永远都不会减的引用计数!
try_module_get(o);
return 0;
}
static void __exit
my_cleanup_module(void)
{
}
module_init(bug4_register);
module_exit(my_cleanup_module);
MODULE_AUTHOR("aaaa");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("bug");
一切编译工作都完成后,我们试着加载bug4.ko,然后运行:
rmmod --wait bug4
此时rmmod就变成D进程了!当我们以rmmod进程的pid为参数载入pidrm模块的时候,该rmmod进程将被杀死!
相关文章推荐
- Linux x86_64内核终止D状态的进程
- Linux内核调试技术——进程D状态死锁检测
- Linux如何终止D状态的进程
- linux下进程的状态,创建,替换,等待,终止
- Linux进程状态(ps stat)之R、S、D、T、Z、X
- linux内核的idle进程分析
- linux c (4) 进程终止-exit和_exit函数
- linux 0.12: 内核支持最多进程个数
- [AD_LAB-04003] Linux 2.6.* 内核Capability LSM模块进程特
- linux内核进程调度(自旋锁)
- Linux 中的新进程状态
- [Pthread] Linux进程终止过程
- 从内核实现看Linux进程与线程
- linux内核进程
- 解析Linux内核获取当前进程指针的方法 [原]
- linux上进程5种状态
- 解析Linux内核获取当前进程指针的方法
- (原创)linux内核进程调度以及定时器实现机制
- 读书笔记--深入理解Linux内核-第七章 进程调度
- Linux 系统下查找进程并终止命令详解