Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 638 Vote(s) - 3.51 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Signals don't re-enable properly across execv()

#1
I am writing a system-critical program for a Linux distribution that I am developing. It needs to restart itself on receiving certain signals, to try to avoid crashing. The problem is, after the restart, I cannot re-enable that signal. That is, the signal cannot be received twice. After execv()'ing itself, when the new process calls signal() to set up the signal, SIG_DFL is returned. Every time. Even if I call it twice in a row -- indicating that it was never set in the first place. Is some weird flag being carried over from the original process?
Reply

#2
Signal handlers aren't inherited across `exec` because `exec` overwrites your whole address space, and any signal handlers that aren't reset would then be pointing to the wrong place. The only time it's not reset is if it's set to, say, `SIG_IGN`, which is not dependent on the address space of the pre-`exec` process.
Reply

#3
You are falling foul of the fact that you are essentially trying to recursively handle a signal.

When using `signal()` to register a signal handler, that signal number is blocked until the signal handler returns - in effect the kernel / libc blocks that signal number when the signal handler is invoked, and unblocks it after the signal handler returns. As you never return from the signal handler (instead you `execl` a new binary), `SIGUSR1` stays blocked and so isn't caught the 2nd time.

This can be seen by examining `/proc/</pid>/status` before and after you send the first `SIGUSR1`.

Before:

$ cat /proc/<pid>/status | grep -E "Sig(Cgt|Blk)"
SigBlk: 0000000000000000
SigCgt: 0000000000000200

After:

$ cat /proc/<pid>/status | grep -E "Sig(Cgt|Blk)"
SigBlk: 0000000000000200
SigCgt: 0000000000000200

Note that `SigCgt` indicates signal 10 is registered (the number is a bitfield; 10th bit is set, which equates to SIGUSR1, see `man signal(7)` for the numbers). `SigBlk` is empty before `SIGUSR` is sent to your process, but after sending the signal it contains `SIGUSR1`.

You have two ways to solve this:

a). Manually unblock `SIGUSR` before calling `execl` in `sighandler`:

sigset_t sigs;
sigprocmask(0, 0, &sigs);
sigdelset(&sigs, SIGUSR1);
sigprocmask(SIG_SETMASK, &sigs);

b). Use `sigaction` with the `SA_NODEFER` flag instead of `signal` to register the signal handler. This will prevent `SIGUSR1` from being blocked inside the signal handler:

struct sigaction act;
act.sa_handler = signalhandler;
act.sa_mask = 0;
act.sa_flags = SA_NODEFER;
sigaction(SIGUSR1, &act, 0);
Reply

#4
I know the question is old but as it brought me into the right direction let me add this here:

For unblocking the signal before spawning the new process with execv() you should use SIG_UNBLOCK. The requirement is described in the signal(7) man-page.

```
void unblock_all_signals()
{
sigset_t sigs;

sigfillset(&sigs);
sigprocmask(SIG_UNBLOCK, &sigs, NULL);
}
```
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through