static int check_kill_permission(int sig, struct siginfo *info, struct task_struct *t)

if ((info == SEND_SIG_NOINFO || (!is_si_special(info) && SI_FROMUSER(info))) && ((sig != SIGCONT) ||

(task_session_nr(current) != task_session_nr(t))) && (current->euid A t->suid) && (current->euid A t->uid) && (current->uid a t->suid) && (current->uid a t->uid) && !capable(CAP_KILL)) return -EPERM;

It could be helpful to remember that the A operator implements an XOR operation, but otherwise the checks are rather straightforward.

The remaining signal handling work is passed on to specific_send_sig_info.

□ If the signal is blocked (this can be checked with sig_ignored), handling is aborted immediately to prevent further waste of time.

□ send_signal generates a new sigqueue instance (using the cache sigqueue_cachep), which is filled with the signal data and added to the sigpending list of the target process.

□ If the signal is delivered successfully and is not blocked, the process is woken with signal_wake_up so that it is available for selection by the scheduler. The tif_sigpending flag is also set to indicate to the kernel that it must deliver signals to the process.

Although the signal is sent after these actions, it does not trigger the signal handler. How this is done is described below.

Processing the Signal Queue

Signal queue processing is not triggered by a system call but is initiated by the kernel each time a switch is made from kernel mode to user mode, as mentioned in Chapter 14. Implementation is naturally very architecture-specific because processing is initiated in the assembly language code of entry.s. Regardless of the particular architecture, the ultimate effect of the actions performed is to invoke the do_signal function, which, although also platform-specific, behaves in much the same way on all systems.

□ get_signal_to_deliver gathers all information on the next signal to be delivered. It also removes the signal from the process-specific pending list.

□ handle_signal manipulates the user mode stack of the process so that the signal handler is run and not the normal program code after switching from kernel to user mode. This complicated approach is necessary because the handler function may not be executed in kernel mode.

The stack is also modified so that the sigreturn system call is invoked when the handler function terminates. How this is done depends on the particular architecture, but the kernel either writes the required machine code instructions to execute the system call directly onto the stack, or uses some glue that is available in userspace.15 This routine is responsible for restoring the process context so that the application can continue to run when the next switch is made to user mode.

Figure 5-10 illustrates the chronological flow and the various switches between user and kernel mode during signal handler execution.

Kernel do.




Handler Function

Continue program execution

Figure 5-10: Signal handler execution.

Continue reading here: Pipes and Sockets

Was this article helpful?

0 0