Commit faf1f22b authored by Eric W. Biederman's avatar Eric W. Biederman

signal: Ensure generic siginfos the kernel sends have all bits initialized

Call clear_siginfo to ensure stack allocated siginfos are fully
initialized before being passed to the signal sending functions.

This ensures that if there is the kind of confusion documented by
TRAP_FIXME, FPE_FIXME, or BUS_FIXME the kernel won't send unitialized
data to userspace when the kernel generates a signal with SI_USER but
the copy to userspace assumes it is a different kind of signal, and
different fields are initialized.

This also prepares the way for turning copy_siginfo_to_user
into a copy_to_user, by removing the need in many cases to perform
a field by field copy simply to skip the uninitialized fields.
Signed-off-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
parent 8c5dbf2a
...@@ -737,6 +737,7 @@ static void send_sigio_to_task(struct task_struct *p, ...@@ -737,6 +737,7 @@ static void send_sigio_to_task(struct task_struct *p,
delivered even if we can't queue. Failure to delivered even if we can't queue. Failure to
queue in this case _should_ be reported; we fall queue in this case _should_ be reported; we fall
back to SIGIO in that case. --sct */ back to SIGIO in that case. --sct */
clear_siginfo(&si);
si.si_signo = signum; si.si_signo = signum;
si.si_errno = 0; si.si_errno = 0;
si.si_code = reason; si.si_code = reason;
......
...@@ -639,6 +639,7 @@ static void __do_notify(struct mqueue_inode_info *info) ...@@ -639,6 +639,7 @@ static void __do_notify(struct mqueue_inode_info *info)
case SIGEV_SIGNAL: case SIGEV_SIGNAL:
/* sends signal */ /* sends signal */
clear_siginfo(&sig_i);
sig_i.si_signo = info->notify.sigev_signo; sig_i.si_signo = info->notify.sigev_signo;
sig_i.si_errno = 0; sig_i.si_errno = 0;
sig_i.si_code = SI_MESGQ; sig_i.si_code = SI_MESGQ;
......
...@@ -549,6 +549,7 @@ static void collect_signal(int sig, struct sigpending *list, siginfo_t *info, ...@@ -549,6 +549,7 @@ static void collect_signal(int sig, struct sigpending *list, siginfo_t *info,
* a fast-pathed signal or we must have been * a fast-pathed signal or we must have been
* out of queue space. So zero out the info. * out of queue space. So zero out the info.
*/ */
clear_siginfo(info);
info->si_signo = sig; info->si_signo = sig;
info->si_errno = 0; info->si_errno = 0;
info->si_code = SI_USER; info->si_code = SI_USER;
...@@ -1043,6 +1044,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, ...@@ -1043,6 +1044,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
list_add_tail(&q->list, &pending->list); list_add_tail(&q->list, &pending->list);
switch ((unsigned long) info) { switch ((unsigned long) info) {
case (unsigned long) SEND_SIG_NOINFO: case (unsigned long) SEND_SIG_NOINFO:
clear_siginfo(&q->info);
q->info.si_signo = sig; q->info.si_signo = sig;
q->info.si_errno = 0; q->info.si_errno = 0;
q->info.si_code = SI_USER; q->info.si_code = SI_USER;
...@@ -1051,6 +1053,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, ...@@ -1051,6 +1053,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
q->info.si_uid = from_kuid_munged(current_user_ns(), current_uid()); q->info.si_uid = from_kuid_munged(current_user_ns(), current_uid());
break; break;
case (unsigned long) SEND_SIG_PRIV: case (unsigned long) SEND_SIG_PRIV:
clear_siginfo(&q->info);
q->info.si_signo = sig; q->info.si_signo = sig;
q->info.si_errno = 0; q->info.si_errno = 0;
q->info.si_code = SI_KERNEL; q->info.si_code = SI_KERNEL;
...@@ -1623,6 +1626,7 @@ bool do_notify_parent(struct task_struct *tsk, int sig) ...@@ -1623,6 +1626,7 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
sig = SIGCHLD; sig = SIGCHLD;
} }
clear_siginfo(&info);
info.si_signo = sig; info.si_signo = sig;
info.si_errno = 0; info.si_errno = 0;
/* /*
...@@ -1717,6 +1721,7 @@ static void do_notify_parent_cldstop(struct task_struct *tsk, ...@@ -1717,6 +1721,7 @@ static void do_notify_parent_cldstop(struct task_struct *tsk,
parent = tsk->real_parent; parent = tsk->real_parent;
} }
clear_siginfo(&info);
info.si_signo = SIGCHLD; info.si_signo = SIGCHLD;
info.si_errno = 0; info.si_errno = 0;
/* /*
...@@ -1929,7 +1934,7 @@ static void ptrace_do_notify(int signr, int exit_code, int why) ...@@ -1929,7 +1934,7 @@ static void ptrace_do_notify(int signr, int exit_code, int why)
{ {
siginfo_t info; siginfo_t info;
memset(&info, 0, sizeof info); clear_siginfo(&info);
info.si_signo = signr; info.si_signo = signr;
info.si_code = exit_code; info.si_code = exit_code;
info.si_pid = task_pid_vnr(current); info.si_pid = task_pid_vnr(current);
...@@ -2136,6 +2141,7 @@ static int ptrace_signal(int signr, siginfo_t *info) ...@@ -2136,6 +2141,7 @@ static int ptrace_signal(int signr, siginfo_t *info)
* have updated *info via PTRACE_SETSIGINFO. * have updated *info via PTRACE_SETSIGINFO.
*/ */
if (signr != info->si_signo) { if (signr != info->si_signo) {
clear_siginfo(info);
info->si_signo = signr; info->si_signo = signr;
info->si_errno = 0; info->si_errno = 0;
info->si_code = SI_USER; info->si_code = SI_USER;
...@@ -2941,6 +2947,7 @@ SYSCALL_DEFINE2(kill, pid_t, pid, int, sig) ...@@ -2941,6 +2947,7 @@ SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)
{ {
struct siginfo info; struct siginfo info;
clear_siginfo(&info);
info.si_signo = sig; info.si_signo = sig;
info.si_errno = 0; info.si_errno = 0;
info.si_code = SI_USER; info.si_code = SI_USER;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment