进程如何分辨谁在kill()自己
2007-09-28 11:17
169 查看
至少对于Linux、FreeBSD、Solaris、AIX这四种操作系统,有一种办法。不要安装传 统sa_handler信号句柄,而是安装sa_sigaction信号句柄。细节请man sigaction并 参照头文件加强理解。下面是一个可移植演示程序。 -------------------------------------------------------------------------- /* * For x86/Linux RedHat_8 2.4.18-14 * For x86/FreeBSD 4.5-RELEASE * For SPARC/Solaris 8 * For AIX 4.3.3.0 * * gcc -Wall -pipe -O3 -s -o siginfo_test siginfo_test.c */ /************************************************************************ * * * Head File * * * ************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include <signal.h> #include <unistd.h> #include <setjmp.h> #include <sys/time.h> /************************************************************************ * * * Macro * * * ************************************************************************/ /* * for signal handlers */ typedef void Sigfunc ( int, siginfo_t *, void * ); #define PRIVATE_SIG_ERR ((Sigfunc *)-1) /************************************************************************ * * * Function Prototype * * * ************************************************************************/ static void Atexit ( void ( * func ) ( void ) ); static void init_signal ( void ); static void init_timer ( unsigned int s ); static void on_alarm ( int signo, siginfo_t *si, void *unused ); static void on_segvbus ( int signo, siginfo_t *si, void *unused ); static void on_terminate ( int signo, siginfo_t *si, void *unused ); static Sigfunc * PrivateSignal ( int signo, Sigfunc *func ); static int Setitimer ( int which, struct itimerval *value, struct itimerval *ovalue ); static Sigfunc * Signal ( int signo, Sigfunc *func ); static void terminate ( void ); /************************************************************************ * * * Static Global Var * * * ************************************************************************/ static sigjmp_buf jmpbuf; static volatile sig_atomic_t canjump = 0; /************************************************************************/ static void Atexit ( void ( * func ) ( void ) ) { if ( atexit( func ) != 0 ) { exit( EXIT_FAILURE ); } return; } /* end of Atexit */ /* * 初始化信号句柄 */ static void init_signal ( void ) { unsigned int i; Atexit( terminate ); for ( i = 1; i < 9; i++ ) { Signal( i, on_terminate ); } Signal( SIGTERM, on_terminate ); Signal( SIGALRM, on_alarm ); Signal( SIGSEGV, on_segvbus ); Signal( SIGBUS , on_segvbus ); return; } /* end of init_signal */ /* * 我们的定时器精度只支持到秒 */ static void init_timer ( unsigned int s ) { struct itimerval value; value.it_value.tv_sec = s; value.it_value.tv_usec = 0; /* * 只生效一次 */ value.it_interval.tv_sec = 0; value.it_interval.tv_usec = 0; Setitimer( ITIMER_REAL, &value, NULL ); return; } /* end of init_timer */ static void on_alarm ( int signo, siginfo_t *si, void *unused ) { fprintf ( stderr, "/n" "signo = %d/n" "si = 0x%08X/n" "unused = 0x%08X/n", signo, ( unsigned int )si, ( unsigned int )unused ); if ( NULL != si ) { fprintf ( stderr, "si->si_signo = %d/n" "si->si_errno = %d/n" "si->si_code = %d/n" "si->si_pid = %u/n" "si->si_uid = %u/n" "si->si_status = %d/n" "si->si_addr = 0x%08X/n", si->si_signo, si->si_errno, si->si_code, ( unsigned int )si->si_pid, ( unsigned int )si->si_uid, ( int )si->si_status, ( unsigned int )si->si_addr ); } return; } /* end of on_alarm */ static void on_segvbus ( int signo, siginfo_t *si, void *unused ) { fprintf ( stderr, "/n" "signo = %d/n" "si = 0x%08X/n" "unused = 0x%08X/n", signo, ( unsigned int )si, ( unsigned int )unused ); if ( NULL != si ) { fprintf ( stderr, "si->si_signo = %d/n" "si->si_errno = %d/n" "si->si_code = %d/n" "si->si_pid = %u/n" "si->si_uid = %u/n" "si->si_status = %d/n" "si->si_addr = 0x%08X/n", si->si_signo, si->si_errno, si->si_code, ( unsigned int )si->si_pid, ( unsigned int )si->si_uid, ( int )si->si_status, ( unsigned int )si->si_addr ); } if ( 0 == canjump ) { /* * unexpected signal, ignore */ return; } canjump = 0; /* * jump back to main, don't return */ siglongjmp( jmpbuf, signo ); } /* end of on_segvbus */ /* * 参如下头文件了解siginfo_t定义 * * Linux /usr/include/bits/siginfo.h * FreeBSD /usr/include/sys/signal.h * Solaris /usr/include/sys/siginfo.h * AIX /usr/include/sys/signal.h * * 第三形参不推荐使用,context相关。 */ static void on_terminate ( int signo, siginfo_t *si, void *unused ) { /* * 就上四种OS而言,测试Solaris,执行siginfo_test,按Ctrl-C进入该流程时 * si为NULL,其他三种系统则不同。 */ if ( NULL != si ) { /* * 演示用,不推荐在信号句柄中使用fprintf() */ fprintf ( stderr, "/n" "signo = %d/n" "si = 0x%08X/n" "unused = 0x%08X/n" "si->si_signo = %d/n" "si->si_errno = %d/n" "si->si_code = %d/n", signo, ( unsigned int )si, ( unsigned int )unused, si->si_signo, si->si_errno, si->si_code ); /* * si_code为SI_USER时意味着"signal sent by another process with kill()" * * 就上四种OS而言,我所测试的FreeBSD反应与其他三种不同,kill进程时 * si_code始终为0,而FreeBSD有如下定义: * * #define SI_USER 0x10001 * * 如果不判断si_code,强行显示si_pid、si_uid,对于FreeBSD而言总是0。 * 下面出于方便演示目的,没有判断si_code。正确作法应该判断si_code, * 然后显示联合的不同成员。 */ fprintf ( stderr, "si->si_pid = %u/n" "si->si_uid = %u/n" "si->si_status = %d/n" "si->si_addr = 0x%08X/n", ( unsigned int )si->si_pid, ( unsigned int )si->si_uid, ( int )si->si_status, ( unsigned int )si->si_addr ); } else { fprintf ( stderr, "/n" "signo = %d/n" "si = 0x%08X/n" "unused = 0x%08X/n", signo, ( unsigned int )si, ( unsigned int )unused ); } /* * 这次我们使用atexit()函数 */ exit( EXIT_SUCCESS ); } /* end of on_terminate */ /* * 与以前版本不同之处在于使用sa_sigaction,而不是sa_handler。 */ static Sigfunc * PrivateSignal ( int signo, Sigfunc *func ) { #if 0 from Linux /usr/include/bits/sigaction.h struct sigaction { union { /* * Used if SA_SIGINFO is not set. */ __sighandler_t sa_handler; /* * Used if SA_SIGINFO is set. */ void ( *sa_sigaction ) ( int, siginfo_t *, void * ); } __sigaction_handler; #define sa_handler __sigaction_handler.sa_handler #define sa_sigaction __sigaction_handler.sa_sigaction /* * Additional set of signals to be blocked. */ __sigset_t sa_mask; /* * Special flags. */ int sa_flags; /* * The sa_restorer element is obsolete and should not be used. * POSIX does not specify a sa_restorer element. * * Restore handler. */ void ( *sa_restorer ) ( void ); }; #endif struct sigaction act, oact; memset( &act, 0, sizeof( act ) ); sigemptyset( &act.sa_mask ); /* * Invoke signal-catching function with three arguments instead of one. */ act.sa_flags = SA_SIGINFO; act.sa_sigaction = func; if ( SIGALRM == signo ) { #ifdef SA_INTERRUPT /* * SunOS 4.x */ act.sa_flags |= SA_INTERRUPT; #endif } else { #ifdef SA_RESTART /* * SVR4, 4.4BSD */ act.sa_flags |= SA_RESTART; #endif } if ( sigaction( signo, &act, &oact ) < 0 ) { return( PRIVATE_SIG_ERR ); } return( oact.sa_sigaction ); } /* end of PrivateSignal */ static int Setitimer ( int which, struct itimerval *value, struct itimerval *ovalue ) { int ret; if ( ( ret = setitimer( which, value, ovalue ) ) < 0 ) { perror( "setitimer error" ); exit( EXIT_FAILURE ); } return( ret ); } /* end of Setitimer */ static Sigfunc * Signal ( int signo, Sigfunc *func ) { Sigfunc *sigfunc; if ( PRIVATE_SIG_ERR == ( sigfunc = PrivateSignal( signo, func ) ) ) { perror( "signal error" ); exit( EXIT_FAILURE ); } return( sigfunc ); } /* end of Signal */ static void terminate ( void ) { /* * _exit( EXIT_SUCCESS ); */ return; } /* end of terminate */ int main ( int argc, char * argv[] ) { /* * for autovar, must be volatile */ volatile unsigned char *p; init_signal(); p = ( unsigned char * )&p; if ( 0 != sigsetjmp( jmpbuf, 1 ) ) { printf ( "p = 0x%08X/n", ( unsigned int )p ); goto main_continue; } /* * now sigsetjump() is OK */ canjump = 1; while ( 1 ) { /* * 诱发SIGSEGV、SIGBUS */ *p = *p; p++; } main_continue: /* * 启动定时器 */ init_timer( 1 ); while ( 1 ) { /* * 形成阻塞,降低CPU占用率 */ getchar(); } return( EXIT_SUCCESS ); } /* end of main */ /************************************************************************/ -------------------------------------------------------------------------- 这种技术是操作系统实现相关的。FreeBSD的si_code与头文件不相符。除了FreeBSD, 其他三种OS的si_addr如愿反映了栈底地址、si_pid/si_uid也能正确反映kill()信号 源。而Solaris会出现si为NULL的情形。下面是Linux上执行示例: [scz@ /home/scz/src]> ./siginfo_test signo = 11 si = 0xBFFFF6B0 unused = 0xBFFFF730 si->si_signo = 11 si->si_errno = 0 si->si_code = 1 si->si_pid = 3221225472 si->si_uid = 1869479936 si->si_status = 2712942 si->si_addr = 0xC0000000 <= 栈底地址 p = 0xC0000000 signo = 14 si = 0xBFFFF5A8 unused = 0xBFFFF628 si->si_signo = 14 si->si_errno = 0 si->si_code = 128 <= SI_KERNEL 0x80 Send by kernel. si->si_pid = 0 si->si_uid = 0 si->si_status = 896820224 si->si_addr = 0x00000000 ^Z [scz@ /home/scz/src]> bg %1 [scz@ /home/scz/src]> kill %1 signo = 15 si = 0xBFFFF5A8 unused = 0xBFFFF628 si->si_signo = 15 si->si_errno = 0 si->si_code = 0 <= SI_USER 0x00 Sent by kill, sigsend, raise. si->si_pid = 27712 <= kill()信号源 si->si_uid = 1000 <= kill()信号源 si->si_status = 896820224 si->si_addr = 0x00006C40 [scz@ /home/scz/src]> echo $ 27712 [scz@ /home/scz/src]> id uid=1000(scz) gid=0(root) groups=0(root) [scz@ /home/scz/src]> 最后结论,对于x86/FreeBSD 4.5-RELEASE,无法利用该技术分辨kill()信号源。其 他三种操作系统可以利用该技术。 一个有趣的想法,进程分辨出kill()信号源,反向kill信号源。
相关文章推荐
- 如何让自己的Android Service永不被系统kill--Android进程永存方法
- 如何防止自己的子程序成为僵尸进程
- ORACLE10G如何用alter system kill session 清除死锁进程
- 如何kill杀掉linux系统中的僵尸defunct进程
- Kill 不只是kill,也可发信号给自己的进程
- Android 系统如何Kill进程当系统内存不足【原理】
- 如何kill杀掉linux系统中的僵尸defunct进程
- 如何kill一个App进程
- Linux下命令行如何KILL掉一个进程?
- 如何使进程不被360软件Kill掉?(解决方案)
- Android如何保证自己的服务被系统kill后又被系统重启?
- jps命令显示出来的进程如何关闭,如何kill
- 如何查找僵尸进程并Kill之,杀不掉的要查看父进程并杀之
- kill及kill -9的用法及如何实现进程的优雅退出
- 在solaris下如何kill oracle所有进程
- 【C语言】【unix c】如何获得进程自己的PID
- Android Service后台服务进程意外被kill掉之后如何重启
- 如何当使用kill命令结束Java进程时,通知正在执行的Java进程
- 如何让自己的Android程序永不被系统kill
- kill及kill -9的用法及如何实现进程的优雅退出