【问题标题】:Where is the code for default signal handler in ELF binary?ELF 二进制文件中默认信号处理程序的代码在哪里?
【发布时间】:2015-12-14 01:27:57
【问题描述】:

我知道当我们按下 Ctrl+C 时,会产生一个 SIGINT 信号,并且终止进程的默认操作将由内核完成。但是这个终止的代码是从哪里来的呢?它是在 ELF 二进制文件中还是内核为我们做的?我认为它在内核中,这就是为什么我们需要在源代码中自定义处理程序来覆盖信号行为。

任何指针将不胜感激。

【问题讨论】:

    标签: c linux kernel signals


    【解决方案1】:

    这是内核正在为我们做的事情。您可以通过阅读内核源代码中的signal.c 文件找到所有信息。

    内核尝试查找已注册信号处理程序的点从这里开始:http://lxr.free-electrons.com/source/kernel/signal.c#L2257

    2257                 ka = &sighand->action[signr-1];
    2258 
    2259                 /* Trace actually delivered signals. */
    2260                 trace_signal_deliver(signr, &ksig->info, ka);
    2261 
    2262                 if (ka->sa.sa_handler == SIG_IGN) /* Do nothing.  */
    2263                         continue;
    2264                 if (ka->sa.sa_handler != SIG_DFL) {
    2265                         /* Run the handler.  */
    2266                         ksig->ka = *ka;
    2267 
    2268                         if (ka->sa.sa_flags & SA_ONESHOT)
    2269                                 ka->sa.sa_handler = SIG_DFL;
    2270 
    2271                         break; /* will return non-zero "signr" value */
    2272                 }
    

    因此,如果有一个信号处理程序并且它不是“忽略信号”(SIG_IGN)并且如果它不是“默认”处理程序(SIG_DEF),内核将简单地将其标记为正在运行(取决于如果它是一次性的,它将再次将处理程序移动到默认处理程序)。

    但是,如果没有注册信号处理程序,或者是SIG_DEF,内核会检查它是否需要暂停进程,最后内核会声明如下:

    2330                 /*
    2331                  * Anything else is fatal, maybe with a core dump.
    2332                  */
    

    http://lxr.free-electrons.com/source/kernel/signal.c#L2330

    【讨论】:

    • 更多问题——“如果”我提供自己的自定义处理程序?谁将在自定义处理程序中执行代码?逻辑是由环 0 中的操作系统执行还是由环 3 中的进程执行?
    • @bawejakunal:它将在 ring 3 中执行。否则将是一个完整的安全隐患。
    【解决方案2】:

    假设你是kill(theShell, SIGINT)。发生的事情类似于......(不显示内核代码,因为它实际上并不相关)

    1. C 运行时库会将所有参数传递给系统调用sys_kill(),并继续执行执行原始系统调用的汇编代码。
    2. 内核接收参数、执行权限检查等...
    3. 如果进程将相应的信号处理程序设置为SIG_DEF,则内核直接执行相应的默认操作并返回。如果进程将相应的信号处理程序设置为SIG_IGN,则忽略该信号并返回系统调用。否则,请继续。
    4. 信号被放入目标进程的信号队列中,连同发送者等一些信息。
    5. 一旦可以选择目标进程中的线程来接收信号,并且没有将其屏蔽掉,则保存线程的上下文(CPU 寄存器、堆栈指针等)并调用信号处理程序。如果在信号到达时线程处于系统调用中,则系统调用返回-EINTR(为简单起见)并调用处理程序。处理程序返回后,系统调用sys_sigreturn 将自动调用,恢复信号之前的线程状态。
    6. 同时步骤5 发生,kill()ing 进程的系统调用返回。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-16
      • 1970-01-01
      相关资源
      最近更新 更多