之前文章提到服务器上一个过程启动后不到三分钟就挂掉,到底是什么起因挂掉了,这个问题能够写篇文章了。过程死了,无非就两种可能:他杀,自杀。自杀又包含第三方杀害和零碎判死刑。
先来看他杀。
1.他杀
咱们以Java为例,Java程序在main办法运行完就会退出,这种属于他杀。或者像上面这样
System.exit();
这样也属于他杀。
比方上面的代码
public class SelfKill { public static void main(String[] args) throws InterruptedException { while(true){ Thread.sleep(5000); System.exit(4); } }}
运行如下:
[koudai@koudai-pc classes]$ java baicai.other.SelfKill[koudai@koudai-pc classes]$ echo $?4
咱们能用shutdownHook来在临死前记日志。
public class SelfKill { public static void main(String[] args) throws InterruptedException { Runtime.getRuntime().addShutdownHook(new Thread(() -> { System.out.println("敞开利用,开释资源"); })); while(true){ Thread.sleep(2000); System.exit(4); } }}
执行后果
[koudai@koudai-pc classes]$ java baicai.other.SelfKill敞开利用,开释资源
能够看到,无论是被动他杀,还是被他杀,shutdownHook都能放弃现场。那如果是不反对shutdownHook的语言呢,或者程序里没有做Hook,那咱们是不晓得的。另外,不只是他杀shutdownHook能触发,它杀shutdownHook也会被触发。
<u>总结下:对于被动他杀,如果咱们有应用了shutdownHook,是能记录下他杀工夫和现场的。如果是被他杀(歹意后门调用System.exit),并且咱们没有做Hook,那对他杀现场是不知情的。代码里肯定要有欠缺的shutdownHook。</u>
被动他杀是咱们的被动行为,那怎么防止被动他杀呢?方才说了,被动他杀个别是歹意调用System.exit导致,一种是开发者退出的后门,一种是脚本小子退出的后门。System.exit导致JVM间接退出,且没有日志能够查问到是哪个类里的代码导致,因而通常状况下须要屏蔽。System.exit是能够被禁止的,办法就是自定义SecurityManager:
public class SelfSecurityManager extends SecurityManager{ @Override public void checkPermission(Permission perm) { if (perm instanceof java.lang.RuntimePermission) { String name = perm.getName(); if (name != null && name.contains("setSecurityManager")) { throw new SecurityException("System.setSecurityManager denied!"); } } } @Override public void checkPermission(Permission perm, Object context) { // } @Override public void checkExit(int status) { super.checkExit(status); throw new ExitException(status);//自定义异样 }}System.setSecurityManager(new SelfSecurityManager());//main办法中
须要留神的是,你能够自定义SecurityManager,脚本小子也能够自定义。因而光在Java类中自定义SecurityManager是不够的,你须要在JVM启动参数上定义更精密的policy文件,以及爱护本人的SecurityManager不被重置。尤其须要留神不要被反射绕过。
2.自杀
后面说了,不只是他杀shutdownHook能触发,以下场景都会触发 ShutdownHook :
- 代码执行完结,JVM 失常退出
- 利用代码中调用
System#exit
办法 - 利用中产生 OOM 谬误,导致 JVM 敞开
- 终端中应用
Ctrl+C
(非后盾运行) - 被动敞开利用
咱们模仿Ctrl+C试试。如下所示
[koudai@koudai-pc classes]$ java baicai.other.SelfKill^C敞开利用,开释资源[koudai@koudai-pc classes]$
能够看到ctrl+C是能被捕捉到的。那么kill指令能被捕捉吗
[koudai@koudai-pc classes]$ kill 14675[koudai@koudai-pc classes]$ java baicai.other.SelfKill敞开利用,开释资源
能够看到一般的kill是能被捕捉的,那么kill -9呢
[koudai@koudai-pc classes]$ ps -ef|grep Killkoudai 14948 8231 0 00:57 pts/1 00:00:00 java baicai.other.SelfKillkoudai 15235 14640 0 00:58 pts/2 00:00:00 grep --colour=auto Kill[koudai@koudai-pc classes]$ kill -9 14948[koudai@koudai-pc classes]$ java baicai.other.SelfKill已杀死
能够看到kill -9是无奈被过程本身所捕捉的。
到这里就完结了吗?
真正的问题来了,就算我有shutdownHook能记下临终遗嘱,然而最要害的是我无奈晓得是谁杀死了我。尤其是剖析某些木马的场景下
如果是零碎杀死我的,那个别就是OOM,这种状况也还好。
Linux内核有个机制叫OOM killer(Out Of Memory killer),该机制会监控那些占用内存过大,尤其是霎时占用内存很快的过程,而后避免内存耗尽而主动把该过程杀掉。内核检测到零碎内存不足、筛选并杀掉某个过程的过程能够参考内核源代码linux/mm/oom_kill.c,当零碎内存不足的时候,out_of_memory()被触发,而后调用select_bad_process()抉择一个”bad”过程杀掉。
这种OOM,是有日志记录的,能够用上面的办法查看
grep "Out of memory" /var/log/messagessudo dmesg|grep "Out of memory"
零碎杀的,自认倒霉。
最麻烦的是被第三方杀的,比方木马,各种监控脚本,各种sh脚本,我咋样才晓得是哪个过程杀的呢?这就须要用到systemtap了。
3.systemtap应用
systemtap是一个用于简化linux零碎运行状态信息收集的开源工具。它立足于性能诊断和bug调试,对内核及用户态程序提供了动静追踪性能,用户能够自定探测事件来跟踪程序的运行状况,如函数的调用门路、CPU占用和磁盘IO等一系列能够探测的状况。有了systemtap,能够在程序不批改代码,甚至不必重启就能剖析出程序的运行状况。
systemtap 的核心思想是定义一个事件(event),以及给出解决该事件的句柄(Handler)。当一个特定的事件产生时,内核运行该解决句柄,就像疾速调用一个子函数一样,解决完之后复原到内核原始状态。
先来装置它
yum install systemtap systemtap-runtimestap-prepstap -e 'probe begin{printf("Hello, World"); exit();}' #测试验证
因为咱们并不需要高级性能,所以暂不装置内核符号文件。接下来,咱们写一个stap脚本
vim sigmon.stp# 内容如下probe begin{ printf("%-8s %-16s %-5s %-16s %6s %-16s\n", "SPID", "SNAME", "RPID", "RNAME", "SIGNUM", "SIGNAME")}probe signal.send{ if (sig_name == @1 && sig_pid == target()) printf("%-8d %-16s %-5d %-16s %-6d %-16s\n", pid(), execname(), sig_pid, pid_name, sig, sig_name)}
当初咱们须要监控某个过程,就这么调用
(base) [root@VM-0-7-centos ~]# stap -x 28262 sigmon.stp SIGKILLSPID SNAME RPID RNAME SIGNUM SIGNAME 2362819 bash 28262 rsyslogd 9 SIGKILL
这样咱们就晓得28262这个过程是被2362819这个过程,也就是bash所杀死的。
当然,如果不在事先监控,预先咱们是拿不到日志信息的。
如果咱们即不做ShutdownHook,也不应用systemtap进行监控,仅仅靠操作系统自带日志,那咱们是无奈保留死亡现场,也很难晓得谁是过程killed背地的凶手了