从set-user-id程序分叉时,为什么不保留PR_SET_PDEATHSIG?

时间:2018-07-20 09:50:54

标签: signals fork exec

我正在寻找一种让子进程知道其父进程(启动程序/监视程序进程)过早死亡的方法,我认为用prctl设置死亡信号是解决我的问题的完美方法。

这是我的启动功能的主要结构。我确实去除了所有额外的管理工作并记录了日志,以使代码简短而不受干扰。

void MonitoredChild::Launch()
{
    const std::string PathToExe( (boost::filesystem::current_path() / this->BookOfLife.ExeName ).string() );

    pid_t ParentIdBeforeFork = getpid();
    pid_t NewChildID         = fork();

    switch ( NewChildID )
    {
        case -1: //failed to create child
        {
            break;
        }
        case 0: //Child comes here.
        {
            //Reset SIGCHLD, child process should not handle this signal.
            signal( SIGCHLD, SIG_DFL );

            //Set things up with the kernel that we want to be signalled
            //  in case the parent dies.
            int ret( prctl( PR_SET_PDEATHSIG, SIGUSR1 ) );

            if ( ret == -1 )
            {
                exit(1);
            }

            //Check if our parent has not died while setting this up:
            if ( getppid() != ParentIdBeforeFork )
            {
                exit(1);
            }

            //Ready, steady, go!
            execlp( PathToExe.c_str(), PathToExe.c_str(), this->BookOfLife.Arguments.c_str(), (char*)NULL );

            //exec() never returns on success and thus should never reach the next line of code!
            exit(1);
        }
        default: //Parent comes here.
        {
            break;
        }
    }
}

当我从命令行手动运行启动器程序时,这确实像超级按钮一样工作。如果我强行杀死发射器,信号会发送给孩子们,一切都会按照预期死亡。

但是,当我将程序作为守护程序运行时,这会改变。我使用SUID位来防止程序在使用init脚本启动后以root用户身份运行。现在,每当我从该启动程序中派生一个新孩子时,该孩子将在执行时失去先前配置的死亡信号。现在,问题是为什么? prctl的手册页在SUID程序上指出以下内容:

This value is cleared for the child of a fork(2) and (since Linux 2.4.36 / 2.6.23) when executing a set-user-ID or set-group-ID binary.

execve的页面对此进行了说明:

(Since Linux 2.4.36 / 2.6.23) If a set-user-ID or set-group-ID program is being executed, then the parent death signal set by prctl(2) PR_SET_PDEATHSIG flag is cleared.

但是,孩子不是不是 SUID程序!而且我只在孩子本身中设置了死亡信号,因此fork()无法清除该信号。那么为什么仍然清除死亡信号呢?

0 个答案:

没有答案