进程如何分辨谁在kill()自己

171 篇文章 2 订阅
150 篇文章 2 订阅
少对于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信号源。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值