1 |
\chapter{System calls \& Signals} |
\chapter{System calls \& Signals} |
2 |
|
|
3 |
\section{User to Kernel space} |
\section{User to Kernel space} |
4 |
|
|
5 |
System calls are used to perform "low-level" operations on the system. System calls are the bridges between user space and kernel space. So it is the bridge between a user application and the system hardware. |
\textbf{\Large S}ystem calls are used to perform "low-level" operations on the system. System calls are the bridges between user space and kernel space. So it is the bridge between a user application and the system hardware. |
6 |
\par Each system call \footnote{System calls are defined in \url{include/asm-i386/unistd.h}} has its own unique identifying number. The kernel uses this number as an index into a table of system call entry points, which point to where the system calls reside in memory along with the number of arguments that should be passed to them. |
\par Each system call \footnote{System calls are defined in \url{include/asm-i386/unistd.h}} has its own unique identifying number. The kernel uses this number as an index into a table of system call entry points, which point to where the system calls reside in memory along with the number of arguments that should be passed to them. |
7 |
\par When a process makes a system call, the behavior is similar to that with interrupts and exceptions. Like exception handling, the general purpose registers and the number of the system call are pushed onto the stack. And, the system call handler is invoked, which calls the routine within the kernel that will do the actual work. |
\par When a process makes a system call, the behavior is similar to that with interrupts and exceptions. Like exception handling, the general purpose registers and the number of the system call are pushed onto the stack. And, the system call handler is invoked, which calls the routine within the kernel that will do the actual work. |
8 |
\par When a user mode program invokes a system call, the libc library transfers control to kernel mode using software interrupt 0x80 registered during IRQ initialization \footnote{set\_system\_gate(SYSCALL\_VECTOR,\&system\_call); in trap\_init() in \url{arch/i386/kernel/traps.c}} and the kernel executes the system call related function. The system call within the kernel is its counterpart in user space prefixed by sys. So, when user calls fork/clone/vfork, kernel executes sys\_fork/sys\_clone/sys\_vfork function. Since, the system call is invoked from user space in order to enter kernel space,it has to pass through the call gate \footnote{Call gates are used to change priviledge level to perform priviledged operatios. Refer appendix ~\ref{appendix B}.} to ensure that user code moves up to the higher privilege level at a specific location within the kernel. |
\par When a user mode program invokes a system call, the libc library transfers control to kernel mode using software interrupt 0x80 registered during IRQ initialization \footnote{set\_system\_gate(SYSCALL\_VECTOR,\&system\_call); in trap\_init() in \url{arch/i386/kernel/traps.c}} and the kernel executes the system call related function. The system call within the kernel is its counterpart in user space prefixed by sys. So, when user calls fork/clone/vfork, kernel executes sys\_fork/sys\_clone/sys\_vfork function. Since, the system call is invoked from user space in order to enter kernel space,it has to pass through the call gate \footnote{Call gates are used to change priviledge level to perform priviledged operations. Refer appendix ~\ref{appendix B}.} to ensure that user code moves up to the higher privilege level at a specific location within the kernel. |
9 |
\subsection{sys\_call\_table} \index{sys\_call\_table} |
\subsection{sys\_call\_table} \index{sys\_call\_table} |
10 |
The \textit{system\_call} code and the \textit{sys\_call\_table} is defined in the asm code \url{arch/i386/kernel/entry.S} |
The \textit{system\_call} code and the \textit{sys\_call\_table} is defined in the asm code \url{arch/i386/kernel/entry.S} |
11 |
% TODO explain code |
\begin{verbatim} |
12 |
\begin{verbatim} |
|
13 |
|
ENTRY(system_call) # LINE : 230 |
14 |
ENTRY(system_call) # LINE : 230 |
pushl %eax # save orig_eax |
15 |
pushl %eax # save orig_eax |
SAVE_ALL |
16 |
SAVE_ALL |
GET_THREAD_INFO(%ebx) |
17 |
GET_THREAD_INFO(%ebx) |
cmpl $(NR_syscalls), %eax |
18 |
cmpl $(NR_syscalls), %eax |
jae syscall_badsys |
19 |
jae syscall_badsys |
# system call tracing in operation |
20 |
# system call tracing in operation |
testb $_TIF_SYSCALL_TRACE,TI_FLAGS(%ebx) |
21 |
testb $_TIF_SYSCALL_TRACE,TI_FLAGS(%ebx) |
jnz syscall_trace_entry |
22 |
jnz syscall_trace_entry |
syscall_call: |
23 |
syscall_call: |
call *sys_call_table(,%eax,4) |
24 |
call *sys_call_table(,%eax,4) |
movl %eax,EAX(%esp) # store the return value |
25 |
movl %eax,EAX(%esp) # store the return value |
syscall_exit: |
26 |
syscall_exit: |
cli # make sure we don't miss an interrupt |
27 |
cli # make sure we don't miss an interrupt |
# setting need_resched or sigpending |
28 |
# setting need_resched or sigpending |
# between sampling and the iret |
29 |
# between sampling and the iret |
movl TI_FLAGS(%ebx), %ecx |
30 |
movl TI_FLAGS(%ebx), %ecx |
testw $_TIF_ALLWORK_MASK, %cx # current->work |
31 |
testw $_TIF_ALLWORK_MASK, %cx # current->work |
jne syscall_exit_work |
32 |
jne syscall_exit_work |
restore_all: |
33 |
restore_all: |
RESTORE_ALL |
34 |
RESTORE_ALL |
|
35 |
|
\end{verbatim} |
36 |
\end{verbatim} |
The system\_call entry point is explained below. It starts with saving all the registers. The macro GET\_THREAD\_INFO stores the address of current process descriptor to ebx register.\footnote{Process descriptor is obtained by rounding kernel stack pointer to muliple of 8192 (8 KB).} If the system call is invalid, value of \textit{ENOSYS} is returned through the eax regiser. Else, the function takes the value of system call from eax register and uses it to index into the sys\_call\_table. |
37 |
% TODO examples , fork -> sys_fork |
\par As an example, when \textit{fork system call} is invoked using the fork system call, int 0x80 is invoked, with the register \%eax containing the fork exception number. The exception calls the \textit{system\_call} assembly function. The function uses the exception number to index into the sys\_call\_table and invokes the sys\_fork function. [ \textbf{call *sys\_call\_table(,\%eax,4)}]. The second index 4 is the size of the long or function pointer in x86 system. When the funtion returns, it restores all registers using RESTORE\_ALL macro. |
38 |
|
|
39 |
\par Scheduling is performed during a system call, to check if any interrupts, signals are missed. |
\\ \\ \par Scheduling is performed during a system call, to check if any interrupts, signals are missed. |
40 |
|
|
41 |
% TODO explain |
\begin{verbatim} |
42 |
|
|
43 |
\begin{verbatim} |
ALIGN |
44 |
|
work_pending: |
45 |
ALIGN |
testb $_TIF_NEED_RESCHED, %cl |
46 |
work_pending: |
jz work_notifysig |
47 |
testb $_TIF_NEED_RESCHED, %cl |
work_resched: |
48 |
jz work_notifysig |
call schedule |
49 |
work_resched: |
cli # make sure we don't miss an interrupt |
50 |
call schedule |
# setting need_resched or sigpending |
51 |
cli # make sure we don't miss an interrupt |
# between sampling and the iret |
52 |
# setting need_resched or sigpending |
movl TI_FLAGS(%ebx), %ecx |
53 |
# between sampling and the iret |
andl $_TIF_WORK_MASK, %ecx # is there any work to be done other |
54 |
movl TI_FLAGS(%ebx), %ecx |
# than syscall tracing? |
55 |
andl $_TIF_WORK_MASK, %ecx # is there any work to be done other |
jz restore_all |
56 |
# than syscall tracing? |
testb $_TIF_NEED_RESCHED, %cl |
57 |
jz restore_all |
jnz work_resched |
58 |
testb $_TIF_NEED_RESCHED, %cl |
work_notifysig: # deal with pending signals and |
59 |
jnz work_resched |
# notify-resume requests |
60 |
|
testl $(VM_MASK),EFLAGS(%esp) |
61 |
\end{verbatim} |
movl %esp, %eax |
62 |
|
jne work_notifysig_v86 # returning to kernel-space or |
63 |
\par When the system call is invoked , the call number is stored in \textit{\%eax register} and the system call handler is picked from the system\_call\_table as defined below. |
# vm86-space |
64 |
\begin{verbatim} |
xorl %edx, %edx |
65 |
|
call do_notify_resume |
66 |
.data |
jmp restore_all |
67 |
ENTRY(sys_call_table) |
|
68 |
.long sys_ni_syscall /* 0 - old "setup()" system call*/ |
\end{verbatim} |
69 |
.long sys_exit |
|
70 |
.long sys_fork |
As shown in the following text diagram, when a system call is invoked, it finds the address of the corresponding kernel function from \url{arch/i386/kernel/entry.S} assembly code. It saves the system call number in the eax register and uses the ebx register to index into the process (thread) table. And inovkes the appropriate system call from \textit{sys\_call\_table}. |
71 |
.long sys_read |
\par When the system call returns, if checks whether any interrupt or signal missed during the execution of system call. This is performed by jumping to \textit{work\_pending}. If the TIF\_NEED\_RESCHED flag is set, then it calls the schedule function. The flag is a part of CR0 register(Master Status Word) of the i386 architecture and it is set when a task switch occurs. The VM\_MASK bit is also the part of FLAGS register used to emulate virtual 8086 mode. |
72 |
.long sys_write |
\par When the code jumps to \textit{work\_notifysig}, it calls the \texit{do\_notify\_resume} function from \url{arch/i386/kernel/signal.c} to deal with the pending signals. |
73 |
.long sys_open /* 5 */ |
|
74 |
.long sys_close |
\vspace{10pt} \noindent |
75 |
. |
\begin{tabularx}{15cm}{lX} |
76 |
. |
{\bf Table of User \& Kernel space functions} & \\ \\ |
77 |
. |
\\ * USER SPACE * & * KERNEL SPACE * \\ |
78 |
.rept NR_syscalls-(.-sys_call_table)/4 |
----------------------------- & \\ |
79 |
.long sys_ni_syscall |
system call (e.g.fork ) & \\ |
80 |
.endr |
----------------------------- & \\ |
81 |
|
& ------------------------------ \\ |
82 |
\end{verbatim} |
& SAVEALL \\ |
83 |
|
& syscall function \\ |
84 |
\section{Signal data structure in a process} \label{sig:structs} |
& (e.g. sys\_fork ) \\ |
85 |
A Signal is an asynchronous notification to an application, by the kernel.The application can override default actions for signals, by specifying handlers to be invoked on signal occurences. But, only certain signals can be overridden. |
& ------------------------------ \\ |
86 |
\par Signals can only be processed when the process is in user mode. If a signal has been sent to a process that is in kernel mode, it is dealt with immediately on returning to user mode.Since, signals are received by user processes and the signal handlers also represents a thread of execution in user space, they can do anything bounded by user privileges. e.g. open/close files, invoke sytstem calls etc. |
& return from syscall \\ |
87 |
\subsection{signals in task\_struct} |
& ------------------------------ \\ |
88 |
\par The process structure \textit{[task\_struct]} contains following structures related to signals. These are described below, in details. |
& Checking if work\_pending \\ |
89 |
|
& ------------------------------ \\ |
90 |
\begin{verbatim} |
& Checking if work\_resched \\ |
91 |
|
& ------------------------------ \\ |
92 |
/* signal handlers */ |
& For scheduling, call \\ |
93 |
spinlock_t sigmask_lock; /* Protects signal and blocked */ |
& schedule function \\ |
94 |
struct signal_struct *sig; /* signal structure */ |
& ------------------------------ \\ |
95 |
|
& RESTORE\_ALL \\ |
96 |
sigset_t blocked; |
& For pending signals, call \\ |
97 |
struct sigpending pending; /* pending signals */ |
& do\_notify\_resume \\ |
98 |
|
& ------------------------------ \\ |
99 |
unsigned long sas_ss_sp; |
----------------------------- & \\ |
100 |
size_t sas_ss_size; |
system call returns & \\ |
101 |
int (*notifier)(void *priv); |
----------------------------- & \\ |
102 |
void *notifier_data; |
\end{tabularx} |
103 |
sigset_t *notifier_mask; /* new signal notification bit mask */ |
|
104 |
|
\par When the system call is invoked , the call number is stored in \textit{\%eax register} and the system call handler is picked from the system\_call\_table as defined below. The parameters for the system call are not passed using the traditional stack copy method. They are copied to the CPU registers and later copied to kernel mode stack when the sys\_* function starts execution. |
105 |
\end{verbatim} |
\begin{verbatim} |
106 |
|
|
107 |
\subsection{signal\_struct} \index{signal\_struct} |
.data |
108 |
The \textit{signal\_struct} is a generic signal structure defined in \url{include/linux/sched.h}. This contains the signal count per process and the spin-lock to protect the signals over multiple CPUs. It also contains an array of size \textit{\_NSIG} \footnote{NSIG is the maximum number of signals supported.} and of type \textit{k\_sigaction} defined below. This array defines the actions to be taken upon receiving any of the \_NSIG [NSIG = 64] signals. |
ENTRY(sys_call_table) |
109 |
\begin{verbatim} |
.long sys_ni_syscall /* 0 - old "setup()" system call*/ |
110 |
|
.long sys_exit |
111 |
struct signal_struct { |
.long sys_fork |
112 |
atomic_t count; |
.long sys_read |
113 |
struct k_sigaction action[_NSIG]; |
.long sys_write |
114 |
spinlock_t siglock; |
.long sys_open /* 5 */ |
115 |
}; |
.long sys_close |
116 |
|
. |
117 |
struct k_sigaction { |
. |
118 |
struct sigaction sa; |
. |
119 |
}; |
.rept NR_syscalls-(.-sys_call_table)/4 |
120 |
|
.long sys_ni_syscall |
121 |
\end{verbatim} |
.endr |
122 |
|
|
123 |
\subsection{sigset\_t and struct sigaction} |
\end{verbatim} |
124 |
The \textit{sigset\_t} contains a bitmask of 2 words (64 bits), with each bit per signal. This bitmask can be used to check whether any signals are pending for a process or any new signals have arrived. Bit0 corresponds to signal0 and running upwards. An important thing to note here, is that all 64 signals are only available in kernel mode signal handling. At user level, only 32 signals can be handled. Earlier versions of linux used to support only 32 signals in kernel space also. As as result of this, we have oldsigset\_t structure defined in kernel. As a result of this, we also have struct sigaction and struct old\_sigaction defined in \url{include/asm-i386/signal.h}, which differ only in the sigset\_t field. These sigaction structures are used by signal and sigaction system calls explained in section ~\ref{sig:regi}. |
|
125 |
|
\section{Signal data structure in a process} \label{sig:structs} |
126 |
\begin{verbatim} |
A Signal is an asynchronous notification to an application, by the kernel.The application can override default actions for signals, by specifying handlers to be invoked on signal occurences. But, only certain signals can be overridden. |
127 |
|
\par Signals can only be processed when the process is in user mode. If a signal has been sent to a process that is in kernel mode, it is dealt with immediately on returning to user mode.Since, signals are received by user processes and the signal handlers also represents a thread of execution in user space, they can do anything bounded by user privileges. e.g. open/close files, invoke sytstem calls etc. |
128 |
#ifdef __KERNEL__ |
\subsection{signals in task\_struct} |
129 |
typedef struct { |
\par The process structure \textit{[task\_struct]} contains following structures related to signals. These are described below, in details. |
130 |
unsigned long sig[_NSIG_WORDS]; |
|
131 |
} sigset_t; |
\begin{verbatim} |
132 |
#define _NSIG 64 |
|
133 |
#define _NSIG_BPW 32 |
/* signal handlers */ |
134 |
#define _NSIG_WORDS (_NSIG / _NSIG_BPW) |
spinlock_t sigmask_lock; /* Protects signal and blocked */ |
135 |
|
struct signal_struct *sig; /* signal structure */ |
136 |
typedef unsigned long old_sigset_t; |
|
137 |
|
sigset_t blocked; |
138 |
#else |
struct sigpending pending; /* pending signals */ |
139 |
|
|
140 |
#define NSIG 32 |
unsigned long sas_ss_sp; |
141 |
typedef unsigned long sigset_t; |
size_t sas_ss_size; |
142 |
|
int (*notifier)(void *priv); |
143 |
#endif |
void *notifier_data; |
144 |
|
sigset_t *notifier_mask; /* new signal notification bit mask */ |
145 |
struct sigaction { |
|
146 |
__sighandler_t sa_handler; |
\end{verbatim} |
147 |
unsigned long sa_flags; |
|
148 |
void (*sa_restorer)(void); |
\subsection{signal\_struct} \index{signal\_struct} |
149 |
sigset_t sa_mask; /* mask last for extensibility */ |
The \textit{signal\_struct} is a generic signal structure defined in \url{include/linux/sched.h}. This contains the signal count per process and the spin-lock to protect the signals over multiple CPUs. It also contains an array of size \textit{\_NSIG} \footnote{NSIG is the maximum number of signals supported.} and of type \textit{k\_sigaction} defined below. This array defines the actions to be taken upon receiving any of the \_NSIG [NSIG = 64] signals. |
150 |
}; |
\begin{verbatim} |
151 |
|
|
152 |
\end{verbatim} |
struct signal_struct { |
153 |
|
atomic_t count; |
154 |
\subsection{struct sigpending} |
struct k_sigaction action[_NSIG]; |
155 |
The list of pending signals is maintained as circular linked list with header node and reference to tail node. The sigqueue structure contains the \textit{siginfo\_t} structure along with a bitmask. |
spinlock_t siglock; |
156 |
\begin{verbatim} |
}; |
157 |
|
|
158 |
struct sigpending { |
struct k_sigaction { |
159 |
struct sigqueue *head, **tail; |
struct sigaction sa; |
160 |
sigset_t signal; |
}; |
161 |
}; |
|
162 |
|
\end{verbatim} |
163 |
\end{verbatim} |
|
164 |
|
\subsection{sigset\_t and struct sigaction} |
165 |
\section{Registering Signals} \label{sig:regi} |
The \textit{sigset\_t} contains a bitmask of 2 words (64 bits), with each bit per signal. This bitmask can be used to check whether any signals are pending for a process or any new signals have arrived. Bit0 corresponds to signal0 and running upwards. An important thing to note here, is that all 64 signals are only available in kernel mode signal handling. At user level, only 32 signals can be handled. Earlier versions of linux used to support only 32 signals in kernel space also. As a result of this, we have oldsigset\_t structure defined in kernel. As a result of this, we also have struct sigaction and struct old\_sigaction defined in \url{include/asm-i386/signal.h}, which differ only in the sigset\_t field. These sigaction structures are used by signal and sigaction system calls explained in section ~\ref{sig:regi}. |
166 |
When sending a signal to a process, kernel saves the context of the current thread of execution in user-space itself and overwrites the process's thread context with the signal handlers context. While delivering a signal, kernel stores the thread state of the previous thread of execution in the user-stack. |
|
167 |
\par The kernel keeps track of pending signals in each process's process structure. This is a 32-bit value, in user space \footnote{Refer to sigset\_t struct above.} in which each bit represents a single signal. Because it is only one bit per signal, there can only be one signal pending of each type. Its possible that the process to which you want to send the signal is sleeping. If that process is sleeping at an interruptible priority, then the process will be awaken to handle the signal. |
\begin{verbatim} |
168 |
\par Whenever a new signal handler is registered by a process using the \textit{signal or sigaction} system call, the kernel updates invokes the sys\_signal function from \url{kernel/signal.c}, or the sys\_sigaction function from \url{acrh/i386/kernel/signal.c}. These functions update the various signal parameters within kernel signal information. Both of these functions call \textit{do\_sigaction} to update signal statisticks. |
|
169 |
\begin{verbatim} |
#ifdef __KERNEL__ |
170 |
|
typedef struct { |
171 |
/* User space system call */ |
unsigned long sig[_NSIG_WORDS]; |
172 |
sighandler_t signal(int signum, sighandler_t handler); |
} sigset_t; |
173 |
|
#define _NSIG 64 |
174 |
/* sys_signal function */ |
#define _NSIG_BPW 32 |
175 |
asmlinkage unsigned long |
#define _NSIG_WORDS (_NSIG / _NSIG_BPW) |
176 |
sys_signal(int sig, __sighandler_t handler) |
|
177 |
{ |
typedef unsigned long old_sigset_t; |
178 |
struct k_sigaction new_sa, old_sa; |
|
179 |
int ret; |
#else |
180 |
|
|
181 |
new_sa.sa.sa_handler = handler; |
#define NSIG 32 |
182 |
new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK; |
typedef unsigned long sigset_t; |
183 |
|
|
184 |
ret = do_sigaction(sig, &new_sa, &old_sa); |
#endif |
185 |
|
|
186 |
return ret ? ret : (unsigned long)old_sa.sa.sa_handler; |
struct sigaction { |
187 |
} |
__sighandler_t sa_handler; |
188 |
|
unsigned long sa_flags; |
189 |
\end{verbatim} |
void (*sa_restorer)(void); |
190 |
|
sigset_t sa_mask; /* mask last for extensibility */ |
191 |
The function stores the passed handler into new signal handler and calls the do\_sigaction function. If the do\_sigaction function returns success, the old signal handler is returned to the calling process, which can be restored using another signal() system call. |
}; |
192 |
|
|
193 |
\begin{verbatim} |
\end{verbatim} |
194 |
|
|
195 |
/* User space system call */ |
\subsection{struct sigpending} |
196 |
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); |
The list of pending signals is maintained as circular linked list with header node and reference to tail node. The sigqueue structure contains the \textit{siginfo\_t} structure along with a bitmask. |
197 |
|
\begin{verbatim} |
198 |
/* sys_sigaction function */ |
|
199 |
asmlinkage int |
struct sigpending { |
200 |
sys_sigaction(int sig, const struct old_sigaction *act, |
struct sigqueue *head, **tail; |
201 |
struct old_sigaction *oact) |
sigset_t signal; |
202 |
|
}; |
203 |
/* INCOMOPLETE CODE */ |
|
204 |
|
\end{verbatim} |
205 |
if (act) { |
|
206 |
old_sigset_t mask; |
\section{Registering Signal handlers} \label{sig:regi} |
207 |
__get_user(new_ka.sa.sa_flags, &act->sa_flags); |
When sending a signal to a process, kernel saves the context of the current thread of execution in user-space itself and overwrites the process's thread context with the signal handlers context. While delivering a signal, kernel stores the thread state of the previous thread of execution in the user-stack. |
208 |
_get_user(mask, &act->sa_mask); |
\par The kernel keeps track of pending signals in each process's process structure. This is a 32-bit value, in user space \footnote{Refer to sigset\_t struct above.} in which each bit represents a single signal. Because it is only one bit per signal, there can only be one signal pending of each type. Its possible that the process to which you want to send the signal is sleeping. If that process is sleeping at an interruptible priority, then the process will be awaken to handle the signal. |
209 |
siginitset(&new_ka.sa.sa_mask, mask); |
\par Whenever a new signal handler is registered by a process using the \textit{signal or sigaction} system call, the kernel updates invokes the sys\_signal function from \url{kernel/signal.c}, or the sys\_sigaction function from \url{acrh/i386/kernel/signal.c}. These functions update the various signal parameters within kernel signal information. Both of these functions call \textit{do\_sigaction} to update signal statistics. |
210 |
} |
\begin{verbatim} |
211 |
|
|
212 |
ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); |
/* User space system call */ |
213 |
|
sighandler_t signal(int signum, sighandler_t handler); |
214 |
__put_user(old_ka.sa.sa_flags, &oact->sa_flags); |
|
215 |
__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); |
/* sys_signal function */ |
216 |
|
asmlinkage unsigned long |
217 |
\end{verbatim} |
sys_signal(int sig, __sighandler_t handler) |
218 |
|
{ |
219 |
\newline \par The system call sigaction is used to modify the complete signal action associated with a signal rather than merely changing the handler. Hence, it takes the \textit{struct sigation} as function arguments. The kernel function sys\_sigaction uses \textit{\_\_get\_user}\footnote{\_\_get\_user is a privileged operation which works across system memory spaces, user and kernel. See also, copy\_from\_user.} to copy the new sigaction structure from user space to kernel space. And calls the do\_sigaction function. When the function returns, it calls \textit{\_\_put\_user} to copy the old sigaction structure from kernel space to user space. |
struct k_sigaction new_sa, old_sa; |
220 |
|
int ret; |
221 |
\subsection{Function do\_sigaction} |
|
222 |
The function do\_sigaction is described below: |
new_sa.sa.sa_handler = handler; |
223 |
\begin{verbatim} |
new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK; |
224 |
|
|
225 |
int |
ret = do_sigaction(sig, &new_sa, &old_sa); |
226 |
do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact) |
|
227 |
{ |
return ret ? ret : (unsigned long)old_sa.sa.sa_handler; |
228 |
struct k_sigaction *k; |
} |
229 |
|
|
230 |
if (sig < 1 || sig > _NSIG || |
\end{verbatim} |
231 |
(act && (sig == SIGKILL || sig == SIGSTOP))) |
|
232 |
return -EINVAL; /* 1. */ |
The function stores the passed handler into new signal handler and calls the do\_sigaction function. If the do\_sigaction function returns success, the old signal handler is returned to the calling process, which can be restored using another signal() system call. |
233 |
|
|
234 |
k = ¤t->sig->action[sig-1]; /* 2. */ |
\begin{verbatim} |
235 |
|
|
236 |
spin_lock(¤t->sig->siglock); |
/* User space system call */ |
237 |
|
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); |
238 |
if (oact) |
|
239 |
*oact = *k; /* 3. */ |
/* sys_sigaction function */ |
240 |
|
asmlinkage int |
241 |
if (act) { |
sys_sigaction(int sig, const struct old_sigaction *act, |
242 |
*k = *act; /* 4. */ |
struct old_sigaction *oact) |
243 |
sigdelsetmask(&k->sa.sa_mask, sigmask(SIGKILL) | sigmask(SIGSTOP)); |
|
244 |
|
/* INCOMOPLETE CODE */ |
245 |
if (k->sa.sa_handler == SIG_IGN |
|
246 |
|| (k->sa.sa_handler == SIG_DFL |
if (act) { |
247 |
&& (sig == SIGCONT || |
old_sigset_t mask; |
248 |
sig == SIGCHLD || |
__get_user(new_ka.sa.sa_flags, &act->sa_flags); |
249 |
sig == SIGWINCH || |
_get_user(mask, &act->sa_mask); |
250 |
sig == SIGURG))) { |
siginitset(&new_ka.sa.sa_mask, mask); |
251 |
spin_lock_irq(¤t->sigmask_lock); |
} |
252 |
if (rm_sig_from_queue(sig, current)) |
|
253 |
recalc_sigpending(); /* 5. */ |
ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); |
254 |
spin_unlock_irq(¤t->sigmask_lock); |
|
255 |
} |
__put_user(old_ka.sa.sa_flags, &oact->sa_flags); |
256 |
} |
__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); |
257 |
|
|
258 |
spin_unlock(¤t->sig->siglock); |
\end{verbatim} |
259 |
return 0; |
|
260 |
} |
\\ \par The system call sigaction is used to modify the complete signal action associated with a signal rather than merely changing the handler. Hence, it takes the \textit{struct sigaction} as function arguments. The kernel function sys\_sigaction uses \textit{\_\_get\_user}\footnote{\_\_get\_user is a privileged operation which works across system memory spaces, user and kernel. See also, copy\_from\_user.} to copy the new sigaction structure from user space to kernel space. And calls the do\_sigaction function. When the function returns, it calls \textit{\_\_put\_user} to copy the old sigaction structure from kernel space to user space. |
261 |
|
|
262 |
\end{verbatim} |
\subsection{Function do\_sigaction} |
263 |
|
The function do\_sigaction is described below: |
264 |
\begin{enumerate} |
\begin{verbatim} |
265 |
\item The function checks the validity of signal. And compares gig with SIGKILL, SIGSTOP because, Changing the signal handlers of SIGKILL or SIGSTOP is not allowed. |
|
266 |
\item The signal lock used for sigsignal handler for the signal is accessed from the sig field of the current process. Signals start with SIGHUP as number 1, and arrays start with number 0, hence [sig-1] is used. |
int |
267 |
\item This signal handler is stored as old signal handler. The signal lock in the signal\_struct for the process is grabbed, here and released after pending signals are recalculated. |
do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact) |
268 |
\item The new signal handler passed, is stored as signal handler in the current process sig field. |
{ |
269 |
\item For the valid signals, the function removes the signal from the sigqueue and updates the sigqueue structure. For the valid signals, the function removes the signal from the sigqueue and updates the sigqueue structure. The inline function \textit{recalc\_sigpending} defined in \url{include/linux/sched.h} re-calculates signal pending state from the set of locally pending signals, globally pending signals, and blocked signals for the \textbf{current} process. |
struct k_sigaction *k; |
270 |
\begin{verbatim} |
|
271 |
static inline void recalc_sigpending(void) |
if (sig < 1 || sig > _NSIG || |
272 |
{ |
(act && (sig == SIGKILL || sig == SIGSTOP))) |
273 |
if (has_pending_signals(¤t->pending.signal, ¤t->blocked)) |
return -EINVAL; /* 1. */ |
274 |
set_thread_flag(TIF_SIGPENDING); |
|
275 |
else |
k = ¤t->sig->action[sig-1]; /* 2. */ |
276 |
clear_thread_flag(TIF_SIGPENDING); |
|
277 |
} |
spin_lock(¤t->sig->siglock); |
278 |
\end{verbatim} |
|
279 |
\end{enumerate} |
if (oact) |
280 |
|
*oact = *k; /* 3. */ |
281 |
\section{Sending Signals to process} \label{sig:send} |
|
282 |
% TODO |
if (act) { |
283 |
\subsection{Function send\_sig()} |
*k = *act; /* 4. */ |
284 |
% TODO from entry.S |
sigdelsetmask(&k->sa.sa_mask, sigmask(SIGKILL) | sigmask(SIGSTOP)); |
285 |
% send_sig; send_sig_info; deliver_signal; send_signal, signal_wake_up |
|
286 |
% force_sig; force_sig_info;send_sig_info; deliver_signal; send_signal |
if (k->sa.sa_handler == SIG_IGN |
287 |
\section{Response of processes to signals} |
|| (k->sa.sa_handler == SIG_DFL |
288 |
\subsection{Function do\_signal()} |
&& (sig == SIGCONT || |
289 |
% TODO |
sig == SIGCHLD || |
290 |
% do_signal, handle_signal, setup_frame |
sig == SIGWINCH || |
291 |
\begin{verbatim} |
sig == SIGURG))) { |
292 |
movl $__NR_sigreturn |
spin_lock_irq(¤t->sigmask_lock); |
293 |
int $0x80 |
if (rm_sig_from_queue(sig, current)) |
294 |
\end{verbatim} |
recalc_sigpending(); /* 5. */ |
295 |
|
spin_unlock_irq(¤t->sigmask_lock); |
296 |
The "\_\_NR\_sigreturn" system call helps the kernel to restore the previous thread's context. When the signal handler exits, it returns to an area in stack where the kernel had already set the trap to make the signal handler execute the system call transparently. |
} |
297 |
|
} |
298 |
|
|
299 |
|
spin_unlock(¤t->sig->siglock); |
300 |
|
return 0; |
301 |
|
} |
302 |
|
|
303 |
|
\end{verbatim} |
304 |
|
|
305 |
|
\begin{enumerate} |
306 |
|
\item The function checks the validity of signal. And compares gig with SIGKILL, SIGSTOP because, Changing the signal handlers of SIGKILL or SIGSTOP is not allowed. |
307 |
|
\item The signal lock used for sigsignal handler for the signal is accessed from the sig field of the current process. Signals start with SIGHUP as number 1, and arrays start with number 0, hence [sig-1] is used. |
308 |
|
\item This signal handler is stored as old signal handler. The signal lock in the signal\_struct for the process is grabbed, here and released after pending signals are recalculated. |
309 |
|
\item The new signal handler passed, is stored as signal handler in the current process sig field. |
310 |
|
\item For the valid signals, the function removes the signal from the sigqueue and updates the sigqueue structure. For the valid signals, the function removes the signal from the sigqueue and updates the sigqueue structure. The inline function \textit{recalc\_sigpending} defined in \url{include/linux/sched.h} re-calculates signal pending state from the set of locally pending signals, globally pending signals, and blocked signals for the \textbf{current} process. |
311 |
|
\begin{verbatim} |
312 |
|
static inline void recalc_sigpending(void) |
313 |
|
{ |
314 |
|
if (has_pending_signals(¤t->pending.signal, ¤t->blocked)) |
315 |
|
set_thread_flag(TIF_SIGPENDING); |
316 |
|
else |
317 |
|
clear_thread_flag(TIF_SIGPENDING); |
318 |
|
} |
319 |
|
\end{verbatim} |
320 |
|
\end{enumerate} |
321 |
|
|
322 |
|
\section{Sending Signals to process} \label{sig:send} |
323 |
|
When kernel wishes to send a signal to some process, it calls the function \textit{send\_sig}. If the signal needs to be forced, it calls the function \textit{force\_sig}. The difference between the two functions is that send\_sig has an optional parameter which can be passed to ignore the signal. The force\_sig function can not ignore the signal. The parameters is used to indicate whether the signal has come from USEP space or KERNEL space. The examples are given below: |
324 |
|
\begin{enumerate} \label{sig:test} |
325 |
|
\item send\_sig function. If segment violation occurs, send SIGSEGV signal. The siginfo structure value of 1, is dummy. This is explained in send\_signal function.[Section ~\ref{sig:sendsig}] |
326 |
|
\begin{verbatim} |
327 |
|
/* kernel/exec\_domain.c */ |
328 |
|
default_handler(int segment, struct pt_regs *regp) |
329 |
|
{ |
330 |
|
if (current_thread_info()->exec_domain->handler != default_handler) |
331 |
|
current_thread_info()->exec_domain->handler(segment, regp); |
332 |
|
else |
333 |
|
send_sig(SIGSEGV, current, 1); |
334 |
|
} |
335 |
|
\end{verbatim} |
336 |
|
\item force\_sig function. For trap exeption, send the signal using force\_sig. |
337 |
|
\begin{verbatim} |
338 |
|
/* arch/i386/kernel/traps.c */ |
339 |
|
trap_signal: { |
340 |
|
struct task_struct *tsk = current; |
341 |
|
tsk->thread.error_code = error_code; |
342 |
|
tsk->thread.trap_no = trapnr; |
343 |
|
force_sig(signr, tsk); |
344 |
|
\end{verbatim} |
345 |
|
\end{enumerate} |
346 |
|
The send\_sig and force\_sig functions are explained below in detail. |
347 |
|
\subsection{Functions send\_sig() \& force\_sig()} |
348 |
|
The basic operation performed by both of theses is functions is to update the sigpending structure of process and wake that process to handle the signal. The kernel performs this in following steps. Note, All these functions are defined in \utl{kernel/signal.c}. |
349 |
|
\begin{itemize} |
350 |
|
\item \textit{send\_sig\_info()} \& \textit{force\_sig\_info()} |
351 |
|
\par These functions are the wrappers for the send\_sig and force\_sig functions. They are kept for backward compatibility with the other kernel source. The force\_sig\_info function changes the signhandler from ignore [SIG\_IGN] to default [SIG\_DFL] and calls the send\_sig\_info function. Thus, from this point onwards both the functions show similar bahaviour. |
352 |
|
\par The send\_sig\_info functions performs the signal sanity checks by checking for bad\_signal, ignored\_signal and calls the deliver\_signal function. |
353 |
|
|
354 |
|
\item \textit{bad\_signal()} |
355 |
|
\par This function checks if the signal is valid or not. It also checks whether the effective process ids of the process are matching with the current process ids. |
356 |
|
|
357 |
|
\item \textit{handle\_stop\_signal()} |
358 |
|
\par The function deals with the signals related to process stopping, viz. SIGKILL, SIGSTOP, SIGCONT, SIGSTP and so on. If any of these signals is to sent, it wakes up the process and then removes unwanted signals from signal queue. |
359 |
|
|
360 |
|
\item \textit{ignored\_signal()} |
361 |
|
\par The function deals with ignoring or posting of the signal. The functions performs follwing actions depending on the signal type. The remaining set of functions are not invoked for signals of type 0. |
362 |
|
\begin{verbatim} |
363 |
|
* Signal type: |
364 |
|
* < 0 : global action (kill - spread to all non-blocked threads) |
365 |
|
* = 0 : ignored |
366 |
|
* > 0 : wake up. |
367 |
|
\end{verbatim} |
368 |
|
|
369 |
|
\item \textit{deliver\_signal()} |
370 |
|
\par This function invokes the send\_signal function by passing the pending signals of the task as argument. If send\_signal returns Success [0], and if the signal to be send is NOT blocked by the process, it wakes up the receiving process. |
371 |
|
|
372 |
|
\section{Function send\_signal()} \label{sig:sendsig} |
373 |
|
\item \textit{send\_signal()} |
374 |
|
\begin{verbatim} |
375 |
|
if (atomic_read(&nr_queued_signals) < max_queued_signals) { |
376 |
|
q = kmem_cache_alloc(sigqueue_cachep, GFP_ATOMIC); |
377 |
|
} |
378 |
|
|
379 |
|
if (q) { |
380 |
|
atomic_inc(&nr_queued_signals); |
381 |
|
q->next = NULL; |
382 |
|
*signals->tail = q; |
383 |
|
signals->tail = &q->next; |
384 |
|
switch ((unsigned long) info) { |
385 |
|
case 0: |
386 |
|
q->info.si_signo = sig; |
387 |
|
q->info.si_errno = 0; |
388 |
|
q->info.si_code = SI_USER; |
389 |
|
q->info.si_pid = current->pid; |
390 |
|
q->info.si_uid = current->uid; |
391 |
|
break; |
392 |
|
case 1: |
393 |
|
q->info.si_signo = sig; |
394 |
|
q->info.si_errno = 0; |
395 |
|
q->info.si_code = SI_KERNEL; |
396 |
|
q->info.si_pid = 0; |
397 |
|
q->info.si_uid = 0; |
398 |
|
break; |
399 |
|
default: |
400 |
|
copy_siginfo(&q->info, info); |
401 |
|
break; |
402 |
|
} |
403 |
|
} else if (sig >= SIGRTMIN && info && (unsigned long)info != 1 |
404 |
|
&& info->si_code != SI_USER) { |
405 |
|
return -EAGAIN; |
406 |
|
} |
407 |
|
|
408 |
|
sigaddset(&signals->signal, sig); |
409 |
|
return 0; |
410 |
|
|
411 |
|
\end{verbatim} |
412 |
|
\par This function allocates a new sigqueue structure \footnote{The sigqueue is allocated by invoking \textit{kmem\_cache\_alloc()} function.} and updates it with the siginfo structure with the info passed as parameter to the function. It also, updated the sigpending structure of the process. |
413 |
|
\par The siginfo structure carried from all the above functions is dummy. This can be verified from the test code seen above [~\ref{sig:test}]. This parameter differenciates the send\_sig or the force\_sig function. A value of 1 indicates that the forceful [KERNEL priviledged signal] and 0 indidates optional singal [coming from USER space]. |
414 |
|
\par Thus, at this point the sigqueue as well as the sigpending structure is updated. |
415 |
|
\item \textit{signal\_wake\_up()} |
416 |
|
\par This function sets the TASK-PENDING bit for the thread associated with the process. Then, if the process is in TASK\_RUNNING state, it calls the kick\_if\_running function. And if the process is in TASK\_INTERRUPTIBLE state, it calls function to wake it up [wake\_up\_process.] |
417 |
|
\item \textit{kick\_if\_running()} |
418 |
|
\par This function is SMP specific and defined in \url{kernel/sched.c}. If the task is running on the current CPU, it prohibites the remote CPUs from running the process to which the signal is to be sent, by rescheduling the tasks. |
419 |
|
\item \textit{wake\_up\_process()} |
420 |
|
\par This function is used to wake up the new process receiving the signal. Please refer to section ~\ref{sched:wakeup} for more details. |
421 |
|
\end{itemize} |
422 |
|
|
423 |
|
\section{Invoking Signal handlers} |
424 |
|
\par Thus, as we have seen in the above section, when a signal is send to a process, the signal structures for the destined process(viz. pending bits) are updated. The linux kernel checks for new signals while returning from an interrupt \textit{(ret\_from\_intr)}, before resuming execution in user space. This is checked for any pending work everytime an interrupt or exception is handled. |
425 |
|
\\ \par The assemble code from \url{arch/i386/kernel/entry.S} is as follows: |
426 |
|
\begin{verbatim} |
427 |
|
ret_from_intr: |
428 |
|
preempt_stop |
429 |
|
DEC_PRE_COUNT(%ebx) |
430 |
|
ret_from_exception: |
431 |
|
movl EFLAGS(%esp), %eax # mix EFLAGS and CS |
432 |
|
movb CS(%esp), %al |
433 |
|
testl $(VM_MASK | 3), %eax |
434 |
|
jz resume_kernel # returning to kernel or vm86-space |
435 |
|
ENTRY(resume_userspace) |
436 |
|
cli |
437 |
|
movl TI_FLAGS(%ebx), %ecx |
438 |
|
andl $_TIF_WORK_MASK, %ecx # is there any work to be done |
439 |
|
jne work_pending |
440 |
|
jmp restore_all |
441 |
|
|
442 |
|
work_pending: |
443 |
|
testb $_TIF_NEED_RESCHED, %cl |
444 |
|
jz work_notifysig |
445 |
|
|
446 |
|
work_notifysig: # deal with pending signals and |
447 |
|
# notify-resume requests |
448 |
|
testl $(VM_MASK),EFLAGS(%esp) |
449 |
|
movl %esp, %eax |
450 |
|
jne work_notifysig_v86 # returning to kernel-space or |
451 |
|
# vm86-space |
452 |
|
xorl %edx, %edx |
453 |
|
call do_notify_resume |
454 |
|
jmp restore_all |
455 |
|
\end{verbatim} |
456 |
|
As shown in the code above, the kernel checks for work\_pending in ret\_from\_intr and ret\_from\_exception. Later, it checks if any non-blocking signals are pending and need servicing and calls the \textit{do\_notify\_resume} function from \url{arch/i386/kernel/signal.c} which effectively calls the famous \textit{do\_signal} function. |
457 |
|
|
458 |
|
\subsection{Function do\_signal()} |
459 |
|
The do\_signal function checks the priviledge level of code segment that entered here. The lower two bits of the segment selector indicate the priviledge level. 0 (binary 00) indicate kernel mode while 3 (binary 11) indicate user mode. If a kernel segment enters here, the function returns back quitely. |
460 |
|
|
461 |
|
\begin{verbatim} |
462 |
|
/* INCOMPLETE CODE */ |
463 |
|
int do_signal(struct pt_regs *regs, sigset_t *oldset) |
464 |
|
{ |
465 |
|
if ((regs->xcs & 3) != 3) |
466 |
|
return 1; |
467 |
|
signr = get_signal_to_deliver(&info, regs); |
468 |
|
if (signr > 0) { |
469 |
|
handle_signal(signr, &info, oldset, regs); |
470 |
|
return 1; |
471 |
|
} |
472 |
|
} |
473 |
|
\end{verbatim} |
474 |
|
Then, the function collects all the signals that need to be delivered using \textit{get\_signal\_to\_deliver}. This function dequeues the signals by repetadely calling \textit{dequeu\_signal} from the signal queue, till there are no pending signals. It also checks for special conditions of signals, e.g. SIGKILL, SIGSTOP, SIGCHLD. If they exits, it notifies the parent process and calls \textit{schedule()} function. Refer to \url{kernel/signal.c} for the architecture independant function. The function deals with the system offered signal handlers here, viz. for signals SIGCONT, SIGSTOP, SIGTTIN, SIGABRT, SIGTRAP, SIGSEGV. The special signals for which the process has registered its own handlers are dealt by calling function \textit{handle\_signal} to dispatch them to the user space processes. The complete mechanism is described below: |
475 |
|
|
476 |
|
\subsubsection{User space signal handlers} |
477 |
|
A signal handler represents a thread of execution in user space just like the main program. They can open files, write files, issue system calls that sleep, and do anything bounded by user privileges. |
478 |
|
\par The only fuzzy thing about signal handlers is that neither the main thread of execution directly call the signal handler nor it knows where it returns. Hence, signal handlers are special, in the sense that \textbf{Signal handlers are functions written in user space and invoked by the kernel. They execute with the priviledge level of user space}. |
479 |
|
\par To achieve this, while delivering signal to user space process, the kernel saves the context of the current thread of execution in user space on the userstack and overwrite the calling process's thread context (one inside the kernel space) with the signal handlers context. |
480 |
|
\\ \par The code is explained below: |
481 |
|
\begin{verbatim} |
482 |
|
static void |
483 |
|
handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset, |
484 |
|
struct pt_regs * regs) |
485 |
|
{ |
486 |
|
struct k_sigaction *ka = ¤t->sig->action[sig-1]; |
487 |
|
/* INCOMPLETE CODE */ |
488 |
|
/* Set up the stack frame */ |
489 |
|
if (ka->sa.sa_flags & SA_SIGINFO) |
490 |
|
setup_rt_frame(sig, ka, info, oldset, regs); |
491 |
|
else |
492 |
|
setup_frame(sig, ka, oldset, regs); |
493 |
|
} |
494 |
|
\end{verbatim} |
495 |
|
The function handle\_signal calls the function setup\_frame or setup\_rt\_frame to set up the environment to execute user space signal handler and return back to kernel mode. both of these functions are similar, with only the difference in frame structure. The setup\_rt\_frame() uses extended frame with an additional element of siginfo structure. Refer to \url{arch/i386/kernel/signal.c} for structures of \textit{sigframe} and \textit{rt\_sigframe}. We describe the setup\_frame function below: |
496 |
|
|
497 |
|
\subsubsection{Function setup\_frame()} |
498 |
|
\begin{verbatim} |
499 |
|
static void setup_frame(int sig, struct k_sigaction *ka, |
500 |
|
sigset_t *set, struct pt_regs * regs) |
501 |
|
{ |
502 |
|
struct sigframe *frame; |
503 |
|
int err = 0; |
504 |
|
|
505 |
|
frame = get_sigframe(ka, regs, sizeof(*frame)); /* 1. */ |
506 |
|
|
507 |
|
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
508 |
|
goto give_sigsegv; |
509 |
|
|
510 |
|
err |= __put_user((current_thread_info()->exec_domain |
511 |
|
&& current_thread_info()->exec_domain->signal_invmap |
512 |
|
&& sig < 32 |
513 |
|
? current_thread_info()->exec_domain->signal_invmap[sig] |
514 |
|
: sig), |
515 |
|
&frame->sig); /* 2. */ |
516 |
|
if (err) |
517 |
|
goto give_sigsegv; |
518 |
|
err |= setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]); |
519 |
|
if (err) /* 3. */ |
520 |
|
goto give_sigsegv; |
521 |
|
|
522 |
|
if (_NSIG_WORDS > 1) { |
523 |
|
err |= __copy_to_user(frame->extramask, &set->sig[1], |
524 |
|
sizeof(frame->extramask)); /* 4. */ |
525 |
|
} |
526 |
|
if (err) |
527 |
|
goto give_sigsegv; |
528 |
|
|
529 |
|
/* Set up to return from userspace. If provided, use a stub |
530 |
|
already in userspace. */ |
531 |
|
if (ka->sa.sa_flags & SA_RESTORER) { |
532 |
|
err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); |
533 |
|
} else { |
534 |
|
err |= __put_user(frame->retcode, &frame->pretcode); |
535 |
|
/* This is popl %eax ; movl $,%eax ; int $0x80 */ |
536 |
|
err |= __put_user(0xb858, (short *)(frame->retcode+0)); |
537 |
|
err |= __put_user(__NR_sigreturn, (int *)(frame->retcode+2)); |
538 |
|
err |= __put_user(0x80cd, (short *)(frame->retcode+6)); |
539 |
|
} /* 5. */ |
540 |
|
|
541 |
|
if (err) |
542 |
|
goto give_sigsegv; |
543 |
|
/* Set up registers for signal handler */ |
544 |
|
regs->esp = (unsigned long) frame; /* 6. */ |
545 |
|
regs->eip = (unsigned long) ka->sa.sa_handler; |
546 |
|
|
547 |
|
set_fs(USER_DS); |
548 |
|
regs->xds = __USER_DS; |
549 |
|
regs->xes = __USER_DS; |
550 |
|
regs->xss = __USER_DS; /* 7. */ |
551 |
|
regs->xcs = __USER_CS; |
552 |
|
regs->eflags &= ~TF_MASK; |
553 |
|
return; |
554 |
|
|
555 |
|
give_sigsegv: |
556 |
|
if (sig == SIGSEGV) |
557 |
|
ka->sa.sa_handler = SIG_DFL; /* 8. */ |
558 |
|
force_sig(SIGSEGV, current); |
559 |
|
|
560 |
|
\end{verbatim} |
561 |
|
|
562 |
|
Initially, the function obtains the appropriate signal frame structure and then calls functions to populate the elements of the sigframe structure. |
563 |
|
\begin{verbatim} |
564 |
|
|
565 |
|
struct sigframe |
566 |
|
{ |
567 |
|
char *pretcode; |
568 |
|
int sig; |
569 |
|
struct sigcontext sc; |
570 |
|
struct _fpstate fpstate; |
571 |
|
unsigned long extramask[_NSIG_WORDS-1]; |
572 |
|
char retcode[8]; |
573 |
|
}; |
574 |
|
\end{verbatim} |
575 |
|
|
576 |
|
\begin{enumerate} |
577 |
|
\item Initially, the function calls get\_sigframe to get frame pointer. This pointer is obtained from the esp (Stack pointer) minus frame size or restorer function pointer if defined. The pointer vulue is cast to sigframe type and used as user mode frame pointer. |
578 |
|
\item Then, the function checks whether the associated exec domain (binary interface) uses reverse signal mappings. If yes, the sig number is saved in the frame using reverse mapping. Otherwise, it is simply copied to stack frame. |
579 |
|
\item Then, the function sets up the signal context for the frame. This involves copying the elements (viz xes, cx, eip, thread info ) of the sigcontext to the stack frame using \textit{\_\_put\_user()} call. Refer to \url{include/asm-i386/sigcontext.h} for sigcontext structure elements. It also copies the floating point registers needed for the frame using \texit{save\_i387()} function call from \url{arch/i386/kernel/i387.c}. |
580 |
|
\item Then, the function copies the extramask used for real time signals to new frame. |
581 |
|
\item This is an important step. The function sets up the sigreturn system call to return back to kernel space after execution of signal handler. This is achieved by invoking sigreturn system call; \textbf{int 0x80h}. |
582 |
|
\item Then, the function sets the instruction pointer and stack frame appropriately so that the signal handler is ready to start execution. So at the end of this function, the current process resumes execution in user mode, with the signal handler. |
583 |
|
\item The function also sets up all segment registers used by the segmentation mechanism to point to user space areas and the signal handler execution begins. |
584 |
|
\item In case, the code violates any segments boundaries and tries to access restricted pages, a segment violation fault is triggered. |
585 |
|
\end{enumerate} |
586 |
|
|
587 |
|
\subsubsection{Signal handler termination} |
588 |
|
\begin{verbatim} |
589 |
|
movl $__NR_sigreturn |
590 |
|
int $0x80 |
591 |
|
\end{verbatim} |
592 |
|
|
593 |
|
The "\_\_NR\_sigreturn" system call helps the kernel to restore the previous thread's context. When the signal handler exits, it returns to an area in stack where the kernel had already set the trap to make the signal handler execute the system call transparently. |
594 |
|
|
595 |
|
\begin{image} |
596 |
|
\begin{verbatim} |
597 |
|
----------------------------- <----- ESP when a sig Handler is invoked. |
598 |
|
Return Address -------------------------- |
599 |
|
----------------------------- | |
600 |
|
sigNumber | | |
601 |
|
----------------------------- | |
602 |
|
struct sigcontext | |
603 |
|
( includes the entire register context ) | |
604 |
|
----------------------------- | |
605 |
|
fpstate | |
606 |
|
----------------------------- | |
607 |
|
extra mask[] | |
608 |
|
----------------------------- | |
609 |
|
popl %eax <--------------------------------- |
610 |
|
movl $__NR_sigreturn |
611 |
|
int $0x80 |
612 |
|
----------------------------- |
613 |
|
/* |
614 |
|
* STACK high address. Grows upwards. |
615 |
|
* The entire context of previous thread is accessible to the |
616 |
|
* signal handler althoug this is not documented. One can |
617 |
|
* verify this information with the linux kernel sources. |
618 |
|
* See the data structure "struct sigframe". |
619 |
|
*/ |
620 |
|
|
621 |
|
asmlinkage int sys_sigreturn(unsigned long __unused) |
622 |
|
{ |
623 |
|
/* INCOMPLETE CODE */ |
624 |
|
struct sigframe *frame = (struct sigframe *)(regs->esp - 8); |
625 |
|
|
626 |
|
if (restore_sigcontext(regs, &frame->sc, &eax)) |
627 |
|
goto badframe; |
628 |
|
return eax; |
629 |
|
} |
630 |
|
|
631 |
|
\end{verbatim} |
632 |
|
\end{image} |
633 |
|
When the sigreturn system call is invoked, it calls sys\_sigreturn kernel function to return to kernel mode. The kernel stack frame is retrived using the esp pointer of regs.\footnote{Recall that the function arguments to a system call are not passed through the stack frame, but using the CPU registers.}. The complete kernel signal context is restored back by calling \texit{restore\_signcontext} which sets upt the appropriate values of segments (fs,cs,es) and registers(esp, esi, eip) etc. |