[PATCH] make fork() atomic wrt pgrp/session signals

Eric W. Biederman wrote:
>
> Ok. SUSV3/Posix is clear, fork is atomic with respect
> to signals. Either a signal comes before or after a
> fork but not during. (See the rationale section).
> http://www.opengroup.org/onlinepubs/000095399/functions/fork.html
>
> The tasklist_lock does not stop forks from adding to a process
> group. The forks stall while the tasklist_lock is held, but a fork
> that began before we grabbed the tasklist_lock simply completes
> afterwards, and the child does not receive the signal.

This also means that SIGSTOP or sig_kernel_coredump() signal can't
be delivered to pgrp/session reliably.

With this patch copy_process() returns -ERESTARTNOINTR when it
detects a pending signal, fork() will be restarted transparently
after handling the signals.

This patch also deletes now unneeded "group_stop_count > 0" check,
copy_process() can no longer succeed while group stop in progress.

Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Acked-By: Eric Biederman <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Oleg Nesterov and committed by
Linus Torvalds
4a2c7a78 47e65328

+17 -20
+17 -20
kernel/fork.c
··· 1136 1136 !cpu_online(task_cpu(p)))) 1137 1137 set_task_cpu(p, smp_processor_id()); 1138 1138 1139 - /* 1140 - * Check for pending SIGKILL! The new thread should not be allowed 1141 - * to slip out of an OOM kill. (or normal SIGKILL.) 1142 - */ 1143 - if (sigismember(&current->pending.signal, SIGKILL)) { 1144 - write_unlock_irq(&tasklist_lock); 1145 - retval = -EINTR; 1146 - goto bad_fork_cleanup_namespace; 1147 - } 1148 - 1149 1139 /* CLONE_PARENT re-uses the old parent */ 1150 1140 if (clone_flags & (CLONE_PARENT|CLONE_THREAD)) 1151 1141 p->real_parent = current->real_parent; ··· 1144 1154 p->parent = p->real_parent; 1145 1155 1146 1156 spin_lock(&current->sighand->siglock); 1157 + 1158 + /* 1159 + * Process group and session signals need to be delivered to just the 1160 + * parent before the fork or both the parent and the child after the 1161 + * fork. Restart if a signal comes in before we add the new process to 1162 + * it's process group. 1163 + * A fatal signal pending means that current will exit, so the new 1164 + * thread can't slip out of an OOM kill (or normal SIGKILL). 1165 + */ 1166 + recalc_sigpending(); 1167 + if (signal_pending(current)) { 1168 + spin_unlock(&current->sighand->siglock); 1169 + write_unlock_irq(&tasklist_lock); 1170 + retval = -ERESTARTNOINTR; 1171 + goto bad_fork_cleanup_namespace; 1172 + } 1173 + 1147 1174 if (clone_flags & CLONE_THREAD) { 1148 1175 /* 1149 1176 * Important: if an exit-all has been started then ··· 1176 1169 1177 1170 p->group_leader = current->group_leader; 1178 1171 list_add_tail_rcu(&p->thread_group, &p->group_leader->thread_group); 1179 - 1180 - if (current->signal->group_stop_count > 0) { 1181 - /* 1182 - * There is an all-stop in progress for the group. 1183 - * We ourselves will stop as soon as we check signals. 1184 - * Make the new thread part of that group stop too. 1185 - */ 1186 - current->signal->group_stop_count++; 1187 - set_tsk_thread_flag(p, TIF_SIGPENDING); 1188 - } 1189 1172 1190 1173 if (!cputime_eq(current->signal->it_virt_expires, 1191 1174 cputime_zero) ||