I know that when we hit Ctrl+C, a SIGINT signal will be raised and the default action of terminating the process will be done by kernel. But where is the code for this termination coming from? Is it in the ELF binary or the kernel does it for us? I presume it is in the kernel and that is why we need custom handlers in our source code to override the signal behavior.
Any pointers will be much appreciated.
It is something kernel is doing for us. You can find all the information by reading signal.c
file in kernel sources.
The point where kernel is trying to find a registered signal handler starts here: https://elixir.bootlin.com/linux/v6.11.3/source/kernel/signal.c#L2809
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 }
So, if there's a signal handler and if it is not "ignore signal" (SIG_IGN
) and if it is not "default" handler (SIG_DEF
), kernel will simply mark it for being run (and depending if it's one-shot it will move handler to default handler again).
However, if there's no signal handler registered, or if it is SIG_DEF
, kernel checks if maybe it needs to pause the process, and finally kernel states the following:
2330 /*
2331 * Anything else is fatal, maybe with a core dump.
2332 */
https://elixir.bootlin.com/linux/v6.11.3/source/kernel/signal.c#L2885