|
@@ -78,6 +78,10 @@ static bool sig_task_ignored(struct task_struct *t, int sig, bool force)
|
|
|
|
|
|
handler = sig_handler(t, sig);
|
|
|
|
|
|
+ /* SIGKILL and SIGSTOP may not be sent to the global init */
|
|
|
+ if (unlikely(is_global_init(t) && sig_kernel_only(sig)))
|
|
|
+ return true;
|
|
|
+
|
|
|
if (unlikely(t->signal->flags & SIGNAL_UNKILLABLE) &&
|
|
|
handler == SIG_DFL && !(force && sig_kernel_only(sig)))
|
|
|
return true;
|
|
@@ -172,6 +176,7 @@ void recalc_sigpending(void)
|
|
|
clear_thread_flag(TIF_SIGPENDING);
|
|
|
|
|
|
}
|
|
|
+EXPORT_SYMBOL(recalc_sigpending);
|
|
|
|
|
|
void calculate_sigpending(void)
|
|
|
{
|
|
@@ -462,6 +467,7 @@ void flush_signals(struct task_struct *t)
|
|
|
flush_sigqueue(&t->signal->shared_pending);
|
|
|
spin_unlock_irqrestore(&t->sighand->siglock, flags);
|
|
|
}
|
|
|
+EXPORT_SYMBOL(flush_signals);
|
|
|
|
|
|
#ifdef CONFIG_POSIX_TIMERS
|
|
|
static void __flush_itimer_signals(struct sigpending *pending)
|
|
@@ -543,7 +549,7 @@ bool unhandled_signal(struct task_struct *tsk, int sig)
|
|
|
return !tsk->ptrace;
|
|
|
}
|
|
|
|
|
|
-static void collect_signal(int sig, struct sigpending *list, siginfo_t *info,
|
|
|
+static void collect_signal(int sig, struct sigpending *list, kernel_siginfo_t *info,
|
|
|
bool *resched_timer)
|
|
|
{
|
|
|
struct sigqueue *q, *first = NULL;
|
|
@@ -589,7 +595,7 @@ still_pending:
|
|
|
}
|
|
|
|
|
|
static int __dequeue_signal(struct sigpending *pending, sigset_t *mask,
|
|
|
- siginfo_t *info, bool *resched_timer)
|
|
|
+ kernel_siginfo_t *info, bool *resched_timer)
|
|
|
{
|
|
|
int sig = next_signal(pending, mask);
|
|
|
|
|
@@ -604,7 +610,7 @@ static int __dequeue_signal(struct sigpending *pending, sigset_t *mask,
|
|
|
*
|
|
|
* All callers have to hold the siglock.
|
|
|
*/
|
|
|
-int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
|
|
|
+int dequeue_signal(struct task_struct *tsk, sigset_t *mask, kernel_siginfo_t *info)
|
|
|
{
|
|
|
bool resched_timer = false;
|
|
|
int signr;
|
|
@@ -680,6 +686,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
|
|
|
#endif
|
|
|
return signr;
|
|
|
}
|
|
|
+EXPORT_SYMBOL_GPL(dequeue_signal);
|
|
|
|
|
|
/*
|
|
|
* Tell a process that it has a new active signal..
|
|
@@ -730,12 +737,12 @@ static void flush_sigqueue_mask(sigset_t *mask, struct sigpending *s)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static inline int is_si_special(const struct siginfo *info)
|
|
|
+static inline int is_si_special(const struct kernel_siginfo *info)
|
|
|
{
|
|
|
- return info <= SEND_SIG_FORCED;
|
|
|
+ return info <= SEND_SIG_PRIV;
|
|
|
}
|
|
|
|
|
|
-static inline bool si_fromuser(const struct siginfo *info)
|
|
|
+static inline bool si_fromuser(const struct kernel_siginfo *info)
|
|
|
{
|
|
|
return info == SEND_SIG_NOINFO ||
|
|
|
(!is_si_special(info) && SI_FROMUSER(info));
|
|
@@ -760,7 +767,7 @@ static bool kill_ok_by_cred(struct task_struct *t)
|
|
|
* Bad permissions for sending the signal
|
|
|
* - the caller must hold the RCU read lock
|
|
|
*/
|
|
|
-static int check_kill_permission(int sig, struct siginfo *info,
|
|
|
+static int check_kill_permission(int sig, struct kernel_siginfo *info,
|
|
|
struct task_struct *t)
|
|
|
{
|
|
|
struct pid *sid;
|
|
@@ -1003,7 +1010,7 @@ static inline bool legacy_queue(struct sigpending *signals, int sig)
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_USER_NS
|
|
|
-static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t)
|
|
|
+static inline void userns_fixup_signal_uid(struct kernel_siginfo *info, struct task_struct *t)
|
|
|
{
|
|
|
if (current_user_ns() == task_cred_xxx(t, user_ns))
|
|
|
return;
|
|
@@ -1017,13 +1024,13 @@ static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_str
|
|
|
rcu_read_unlock();
|
|
|
}
|
|
|
#else
|
|
|
-static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t)
|
|
|
+static inline void userns_fixup_signal_uid(struct kernel_siginfo *info, struct task_struct *t)
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
-static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
|
|
|
+static int __send_signal(int sig, struct kernel_siginfo *info, struct task_struct *t,
|
|
|
enum pid_type type, int from_ancestor_ns)
|
|
|
{
|
|
|
struct sigpending *pending;
|
|
@@ -1035,7 +1042,7 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
|
|
|
|
|
|
result = TRACE_SIGNAL_IGNORED;
|
|
|
if (!prepare_signal(sig, t,
|
|
|
- from_ancestor_ns || (info == SEND_SIG_FORCED)))
|
|
|
+ from_ancestor_ns || (info == SEND_SIG_PRIV)))
|
|
|
goto ret;
|
|
|
|
|
|
pending = (type != PIDTYPE_PID) ? &t->signal->shared_pending : &t->pending;
|
|
@@ -1050,10 +1057,10 @@ static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
|
|
|
|
|
|
result = TRACE_SIGNAL_DELIVERED;
|
|
|
/*
|
|
|
- * fast-pathed signals for kernel-internal things like SIGSTOP
|
|
|
- * or SIGKILL.
|
|
|
+ * Skip useless siginfo allocation for SIGKILL SIGSTOP,
|
|
|
+ * and kernel threads.
|
|
|
*/
|
|
|
- if (info == SEND_SIG_FORCED)
|
|
|
+ if (sig_kernel_only(sig) || (t->flags & PF_KTHREAD))
|
|
|
goto out_set;
|
|
|
|
|
|
/*
|
|
@@ -1143,7 +1150,7 @@ ret:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
|
|
|
+static int send_signal(int sig, struct kernel_siginfo *info, struct task_struct *t,
|
|
|
enum pid_type type)
|
|
|
{
|
|
|
int from_ancestor_ns = 0;
|
|
@@ -1190,18 +1197,12 @@ static int __init setup_print_fatal_signals(char *str)
|
|
|
__setup("print-fatal-signals=", setup_print_fatal_signals);
|
|
|
|
|
|
int
|
|
|
-__group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
|
|
|
+__group_send_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *p)
|
|
|
{
|
|
|
return send_signal(sig, info, p, PIDTYPE_TGID);
|
|
|
}
|
|
|
|
|
|
-static int
|
|
|
-specific_send_sig_info(int sig, struct siginfo *info, struct task_struct *t)
|
|
|
-{
|
|
|
- return send_signal(sig, info, t, PIDTYPE_PID);
|
|
|
-}
|
|
|
-
|
|
|
-int do_send_sig_info(int sig, struct siginfo *info, struct task_struct *p,
|
|
|
+int do_send_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *p,
|
|
|
enum pid_type type)
|
|
|
{
|
|
|
unsigned long flags;
|
|
@@ -1227,7 +1228,7 @@ int do_send_sig_info(int sig, struct siginfo *info, struct task_struct *p,
|
|
|
* that is why we also clear SIGNAL_UNKILLABLE.
|
|
|
*/
|
|
|
int
|
|
|
-force_sig_info(int sig, struct siginfo *info, struct task_struct *t)
|
|
|
+force_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *t)
|
|
|
{
|
|
|
unsigned long int flags;
|
|
|
int ret, blocked, ignored;
|
|
@@ -1250,7 +1251,7 @@ force_sig_info(int sig, struct siginfo *info, struct task_struct *t)
|
|
|
*/
|
|
|
if (action->sa.sa_handler == SIG_DFL && !t->ptrace)
|
|
|
t->signal->flags &= ~SIGNAL_UNKILLABLE;
|
|
|
- ret = specific_send_sig_info(sig, info, t);
|
|
|
+ ret = send_signal(sig, info, t, PIDTYPE_PID);
|
|
|
spin_unlock_irqrestore(&t->sighand->siglock, flags);
|
|
|
|
|
|
return ret;
|
|
@@ -1315,8 +1316,8 @@ struct sighand_struct *__lock_task_sighand(struct task_struct *tsk,
|
|
|
/*
|
|
|
* send signal info to all the members of a group
|
|
|
*/
|
|
|
-int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p,
|
|
|
- enum pid_type type)
|
|
|
+int group_send_sig_info(int sig, struct kernel_siginfo *info,
|
|
|
+ struct task_struct *p, enum pid_type type)
|
|
|
{
|
|
|
int ret;
|
|
|
|
|
@@ -1335,7 +1336,7 @@ int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p,
|
|
|
* control characters do (^C, ^Z etc)
|
|
|
* - the caller must hold at least a readlock on tasklist_lock
|
|
|
*/
|
|
|
-int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp)
|
|
|
+int __kill_pgrp_info(int sig, struct kernel_siginfo *info, struct pid *pgrp)
|
|
|
{
|
|
|
struct task_struct *p = NULL;
|
|
|
int retval, success;
|
|
@@ -1350,7 +1351,7 @@ int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp)
|
|
|
return success ? 0 : retval;
|
|
|
}
|
|
|
|
|
|
-int kill_pid_info(int sig, struct siginfo *info, struct pid *pid)
|
|
|
+int kill_pid_info(int sig, struct kernel_siginfo *info, struct pid *pid)
|
|
|
{
|
|
|
int error = -ESRCH;
|
|
|
struct task_struct *p;
|
|
@@ -1372,7 +1373,7 @@ int kill_pid_info(int sig, struct siginfo *info, struct pid *pid)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static int kill_proc_info(int sig, struct siginfo *info, pid_t pid)
|
|
|
+static int kill_proc_info(int sig, struct kernel_siginfo *info, pid_t pid)
|
|
|
{
|
|
|
int error;
|
|
|
rcu_read_lock();
|
|
@@ -1393,7 +1394,7 @@ static inline bool kill_as_cred_perm(const struct cred *cred,
|
|
|
}
|
|
|
|
|
|
/* like kill_pid_info(), but doesn't use uid/euid of "current" */
|
|
|
-int kill_pid_info_as_cred(int sig, struct siginfo *info, struct pid *pid,
|
|
|
+int kill_pid_info_as_cred(int sig, struct kernel_siginfo *info, struct pid *pid,
|
|
|
const struct cred *cred)
|
|
|
{
|
|
|
int ret = -EINVAL;
|
|
@@ -1437,7 +1438,7 @@ EXPORT_SYMBOL_GPL(kill_pid_info_as_cred);
|
|
|
* is probably wrong. Should make it like BSD or SYSV.
|
|
|
*/
|
|
|
|
|
|
-static int kill_something_info(int sig, struct siginfo *info, pid_t pid)
|
|
|
+static int kill_something_info(int sig, struct kernel_siginfo *info, pid_t pid)
|
|
|
{
|
|
|
int ret;
|
|
|
|
|
@@ -1481,7 +1482,7 @@ static int kill_something_info(int sig, struct siginfo *info, pid_t pid)
|
|
|
* These are for backward compatibility with the rest of the kernel source.
|
|
|
*/
|
|
|
|
|
|
-int send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
|
|
|
+int send_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *p)
|
|
|
{
|
|
|
/*
|
|
|
* Make sure legacy kernel users don't send in bad values
|
|
@@ -1492,6 +1493,7 @@ int send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
|
|
|
|
|
|
return do_send_sig_info(sig, info, p, PIDTYPE_PID);
|
|
|
}
|
|
|
+EXPORT_SYMBOL(send_sig_info);
|
|
|
|
|
|
#define __si_special(priv) \
|
|
|
((priv) ? SEND_SIG_PRIV : SEND_SIG_NOINFO)
|
|
@@ -1501,11 +1503,13 @@ send_sig(int sig, struct task_struct *p, int priv)
|
|
|
{
|
|
|
return send_sig_info(sig, __si_special(priv), p);
|
|
|
}
|
|
|
+EXPORT_SYMBOL(send_sig);
|
|
|
|
|
|
void force_sig(int sig, struct task_struct *p)
|
|
|
{
|
|
|
force_sig_info(sig, SEND_SIG_PRIV, p);
|
|
|
}
|
|
|
+EXPORT_SYMBOL(force_sig);
|
|
|
|
|
|
/*
|
|
|
* When things go south during signal handling, we
|
|
@@ -1529,7 +1533,7 @@ int force_sig_fault(int sig, int code, void __user *addr
|
|
|
___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr)
|
|
|
, struct task_struct *t)
|
|
|
{
|
|
|
- struct siginfo info;
|
|
|
+ struct kernel_siginfo info;
|
|
|
|
|
|
clear_siginfo(&info);
|
|
|
info.si_signo = sig;
|
|
@@ -1552,7 +1556,7 @@ int send_sig_fault(int sig, int code, void __user *addr
|
|
|
___ARCH_SI_IA64(int imm, unsigned int flags, unsigned long isr)
|
|
|
, struct task_struct *t)
|
|
|
{
|
|
|
- struct siginfo info;
|
|
|
+ struct kernel_siginfo info;
|
|
|
|
|
|
clear_siginfo(&info);
|
|
|
info.si_signo = sig;
|
|
@@ -1572,7 +1576,7 @@ int send_sig_fault(int sig, int code, void __user *addr
|
|
|
|
|
|
int force_sig_mceerr(int code, void __user *addr, short lsb, struct task_struct *t)
|
|
|
{
|
|
|
- struct siginfo info;
|
|
|
+ struct kernel_siginfo info;
|
|
|
|
|
|
WARN_ON((code != BUS_MCEERR_AO) && (code != BUS_MCEERR_AR));
|
|
|
clear_siginfo(&info);
|
|
@@ -1586,7 +1590,7 @@ int force_sig_mceerr(int code, void __user *addr, short lsb, struct task_struct
|
|
|
|
|
|
int send_sig_mceerr(int code, void __user *addr, short lsb, struct task_struct *t)
|
|
|
{
|
|
|
- struct siginfo info;
|
|
|
+ struct kernel_siginfo info;
|
|
|
|
|
|
WARN_ON((code != BUS_MCEERR_AO) && (code != BUS_MCEERR_AR));
|
|
|
clear_siginfo(&info);
|
|
@@ -1601,7 +1605,7 @@ EXPORT_SYMBOL(send_sig_mceerr);
|
|
|
|
|
|
int force_sig_bnderr(void __user *addr, void __user *lower, void __user *upper)
|
|
|
{
|
|
|
- struct siginfo info;
|
|
|
+ struct kernel_siginfo info;
|
|
|
|
|
|
clear_siginfo(&info);
|
|
|
info.si_signo = SIGSEGV;
|
|
@@ -1616,7 +1620,7 @@ int force_sig_bnderr(void __user *addr, void __user *lower, void __user *upper)
|
|
|
#ifdef SEGV_PKUERR
|
|
|
int force_sig_pkuerr(void __user *addr, u32 pkey)
|
|
|
{
|
|
|
- struct siginfo info;
|
|
|
+ struct kernel_siginfo info;
|
|
|
|
|
|
clear_siginfo(&info);
|
|
|
info.si_signo = SIGSEGV;
|
|
@@ -1633,7 +1637,7 @@ int force_sig_pkuerr(void __user *addr, u32 pkey)
|
|
|
*/
|
|
|
int force_sig_ptrace_errno_trap(int errno, void __user *addr)
|
|
|
{
|
|
|
- struct siginfo info;
|
|
|
+ struct kernel_siginfo info;
|
|
|
|
|
|
clear_siginfo(&info);
|
|
|
info.si_signo = SIGTRAP;
|
|
@@ -1762,7 +1766,7 @@ ret:
|
|
|
*/
|
|
|
bool do_notify_parent(struct task_struct *tsk, int sig)
|
|
|
{
|
|
|
- struct siginfo info;
|
|
|
+ struct kernel_siginfo info;
|
|
|
unsigned long flags;
|
|
|
struct sighand_struct *psig;
|
|
|
bool autoreap = false;
|
|
@@ -1867,7 +1871,7 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
|
|
|
static void do_notify_parent_cldstop(struct task_struct *tsk,
|
|
|
bool for_ptracer, int why)
|
|
|
{
|
|
|
- struct siginfo info;
|
|
|
+ struct kernel_siginfo info;
|
|
|
unsigned long flags;
|
|
|
struct task_struct *parent;
|
|
|
struct sighand_struct *sighand;
|
|
@@ -1967,7 +1971,7 @@ static bool sigkill_pending(struct task_struct *tsk)
|
|
|
* If we actually decide not to stop at all because the tracer
|
|
|
* is gone, we keep current->exit_code unless clear_code.
|
|
|
*/
|
|
|
-static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info)
|
|
|
+static void ptrace_stop(int exit_code, int why, int clear_code, kernel_siginfo_t *info)
|
|
|
__releases(¤t->sighand->siglock)
|
|
|
__acquires(¤t->sighand->siglock)
|
|
|
{
|
|
@@ -2104,7 +2108,7 @@ static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info)
|
|
|
|
|
|
static void ptrace_do_notify(int signr, int exit_code, int why)
|
|
|
{
|
|
|
- siginfo_t info;
|
|
|
+ kernel_siginfo_t info;
|
|
|
|
|
|
clear_siginfo(&info);
|
|
|
info.si_signo = signr;
|
|
@@ -2285,7 +2289,7 @@ static void do_jobctl_trap(void)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static int ptrace_signal(int signr, siginfo_t *info)
|
|
|
+static int ptrace_signal(int signr, kernel_siginfo_t *info)
|
|
|
{
|
|
|
/*
|
|
|
* We do not check sig_kernel_stop(signr) but set this marker
|
|
@@ -2326,7 +2330,7 @@ static int ptrace_signal(int signr, siginfo_t *info)
|
|
|
|
|
|
/* If the (new) signal is now blocked, requeue it. */
|
|
|
if (sigismember(¤t->blocked, signr)) {
|
|
|
- specific_send_sig_info(signr, info, current);
|
|
|
+ send_signal(signr, info, current, PIDTYPE_PID);
|
|
|
signr = 0;
|
|
|
}
|
|
|
|
|
@@ -2636,14 +2640,6 @@ out:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-EXPORT_SYMBOL(recalc_sigpending);
|
|
|
-EXPORT_SYMBOL_GPL(dequeue_signal);
|
|
|
-EXPORT_SYMBOL(flush_signals);
|
|
|
-EXPORT_SYMBOL(force_sig);
|
|
|
-EXPORT_SYMBOL(send_sig);
|
|
|
-EXPORT_SYMBOL(send_sig_info);
|
|
|
-EXPORT_SYMBOL(sigprocmask);
|
|
|
-
|
|
|
/*
|
|
|
* System call entry points.
|
|
|
*/
|
|
@@ -2737,6 +2733,7 @@ int sigprocmask(int how, sigset_t *set, sigset_t *oldset)
|
|
|
__set_current_blocked(&newset);
|
|
|
return 0;
|
|
|
}
|
|
|
+EXPORT_SYMBOL(sigprocmask);
|
|
|
|
|
|
/**
|
|
|
* sys_rt_sigprocmask - change the list of currently blocked signals
|
|
@@ -2847,27 +2844,48 @@ COMPAT_SYSCALL_DEFINE2(rt_sigpending, compat_sigset_t __user *, uset,
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
-enum siginfo_layout siginfo_layout(int sig, int si_code)
|
|
|
+static const struct {
|
|
|
+ unsigned char limit, layout;
|
|
|
+} sig_sicodes[] = {
|
|
|
+ [SIGILL] = { NSIGILL, SIL_FAULT },
|
|
|
+ [SIGFPE] = { NSIGFPE, SIL_FAULT },
|
|
|
+ [SIGSEGV] = { NSIGSEGV, SIL_FAULT },
|
|
|
+ [SIGBUS] = { NSIGBUS, SIL_FAULT },
|
|
|
+ [SIGTRAP] = { NSIGTRAP, SIL_FAULT },
|
|
|
+#if defined(SIGEMT)
|
|
|
+ [SIGEMT] = { NSIGEMT, SIL_FAULT },
|
|
|
+#endif
|
|
|
+ [SIGCHLD] = { NSIGCHLD, SIL_CHLD },
|
|
|
+ [SIGPOLL] = { NSIGPOLL, SIL_POLL },
|
|
|
+ [SIGSYS] = { NSIGSYS, SIL_SYS },
|
|
|
+};
|
|
|
+
|
|
|
+static bool known_siginfo_layout(unsigned sig, int si_code)
|
|
|
+{
|
|
|
+ if (si_code == SI_KERNEL)
|
|
|
+ return true;
|
|
|
+ else if ((si_code > SI_USER)) {
|
|
|
+ if (sig_specific_sicodes(sig)) {
|
|
|
+ if (si_code <= sig_sicodes[sig].limit)
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ else if (si_code <= NSIGPOLL)
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ else if (si_code >= SI_DETHREAD)
|
|
|
+ return true;
|
|
|
+ else if (si_code == SI_ASYNCNL)
|
|
|
+ return true;
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+enum siginfo_layout siginfo_layout(unsigned sig, int si_code)
|
|
|
{
|
|
|
enum siginfo_layout layout = SIL_KILL;
|
|
|
if ((si_code > SI_USER) && (si_code < SI_KERNEL)) {
|
|
|
- static const struct {
|
|
|
- unsigned char limit, layout;
|
|
|
- } filter[] = {
|
|
|
- [SIGILL] = { NSIGILL, SIL_FAULT },
|
|
|
- [SIGFPE] = { NSIGFPE, SIL_FAULT },
|
|
|
- [SIGSEGV] = { NSIGSEGV, SIL_FAULT },
|
|
|
- [SIGBUS] = { NSIGBUS, SIL_FAULT },
|
|
|
- [SIGTRAP] = { NSIGTRAP, SIL_FAULT },
|
|
|
-#if defined(SIGEMT) && defined(NSIGEMT)
|
|
|
- [SIGEMT] = { NSIGEMT, SIL_FAULT },
|
|
|
-#endif
|
|
|
- [SIGCHLD] = { NSIGCHLD, SIL_CHLD },
|
|
|
- [SIGPOLL] = { NSIGPOLL, SIL_POLL },
|
|
|
- [SIGSYS] = { NSIGSYS, SIL_SYS },
|
|
|
- };
|
|
|
- if ((sig < ARRAY_SIZE(filter)) && (si_code <= filter[sig].limit)) {
|
|
|
- layout = filter[sig].layout;
|
|
|
+ if ((sig < ARRAY_SIZE(sig_sicodes)) &&
|
|
|
+ (si_code <= sig_sicodes[sig].limit)) {
|
|
|
+ layout = sig_sicodes[sig].layout;
|
|
|
/* Handle the exceptions */
|
|
|
if ((sig == SIGBUS) &&
|
|
|
(si_code >= BUS_MCEERR_AR) && (si_code <= BUS_MCEERR_AO))
|
|
@@ -2892,22 +2910,69 @@ enum siginfo_layout siginfo_layout(int sig, int si_code)
|
|
|
return layout;
|
|
|
}
|
|
|
|
|
|
-int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
|
|
|
+static inline char __user *si_expansion(const siginfo_t __user *info)
|
|
|
+{
|
|
|
+ return ((char __user *)info) + sizeof(struct kernel_siginfo);
|
|
|
+}
|
|
|
+
|
|
|
+int copy_siginfo_to_user(siginfo_t __user *to, const kernel_siginfo_t *from)
|
|
|
{
|
|
|
- if (copy_to_user(to, from , sizeof(struct siginfo)))
|
|
|
+ char __user *expansion = si_expansion(to);
|
|
|
+ if (copy_to_user(to, from , sizeof(struct kernel_siginfo)))
|
|
|
+ return -EFAULT;
|
|
|
+ if (clear_user(expansion, SI_EXPANSION_SIZE))
|
|
|
return -EFAULT;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int post_copy_siginfo_from_user(kernel_siginfo_t *info,
|
|
|
+ const siginfo_t __user *from)
|
|
|
+{
|
|
|
+ if (unlikely(!known_siginfo_layout(info->si_signo, info->si_code))) {
|
|
|
+ char __user *expansion = si_expansion(from);
|
|
|
+ char buf[SI_EXPANSION_SIZE];
|
|
|
+ int i;
|
|
|
+ /*
|
|
|
+ * An unknown si_code might need more than
|
|
|
+ * sizeof(struct kernel_siginfo) bytes. Verify all of the
|
|
|
+ * extra bytes are 0. This guarantees copy_siginfo_to_user
|
|
|
+ * will return this data to userspace exactly.
|
|
|
+ */
|
|
|
+ if (copy_from_user(&buf, expansion, SI_EXPANSION_SIZE))
|
|
|
+ return -EFAULT;
|
|
|
+ for (i = 0; i < SI_EXPANSION_SIZE; i++) {
|
|
|
+ if (buf[i] != 0)
|
|
|
+ return -E2BIG;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int __copy_siginfo_from_user(int signo, kernel_siginfo_t *to,
|
|
|
+ const siginfo_t __user *from)
|
|
|
+{
|
|
|
+ if (copy_from_user(to, from, sizeof(struct kernel_siginfo)))
|
|
|
+ return -EFAULT;
|
|
|
+ to->si_signo = signo;
|
|
|
+ return post_copy_siginfo_from_user(to, from);
|
|
|
+}
|
|
|
+
|
|
|
+int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from)
|
|
|
+{
|
|
|
+ if (copy_from_user(to, from, sizeof(struct kernel_siginfo)))
|
|
|
+ return -EFAULT;
|
|
|
+ return post_copy_siginfo_from_user(to, from);
|
|
|
+}
|
|
|
+
|
|
|
#ifdef CONFIG_COMPAT
|
|
|
int copy_siginfo_to_user32(struct compat_siginfo __user *to,
|
|
|
- const struct siginfo *from)
|
|
|
+ const struct kernel_siginfo *from)
|
|
|
#if defined(CONFIG_X86_X32_ABI) || defined(CONFIG_IA32_EMULATION)
|
|
|
{
|
|
|
return __copy_siginfo_to_user32(to, from, in_x32_syscall());
|
|
|
}
|
|
|
int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
|
|
|
- const struct siginfo *from, bool x32_ABI)
|
|
|
+ const struct kernel_siginfo *from, bool x32_ABI)
|
|
|
#endif
|
|
|
{
|
|
|
struct compat_siginfo new;
|
|
@@ -2991,88 +3056,106 @@ int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-int copy_siginfo_from_user32(struct siginfo *to,
|
|
|
- const struct compat_siginfo __user *ufrom)
|
|
|
+static int post_copy_siginfo_from_user32(kernel_siginfo_t *to,
|
|
|
+ const struct compat_siginfo *from)
|
|
|
{
|
|
|
- struct compat_siginfo from;
|
|
|
-
|
|
|
- if (copy_from_user(&from, ufrom, sizeof(struct compat_siginfo)))
|
|
|
- return -EFAULT;
|
|
|
-
|
|
|
clear_siginfo(to);
|
|
|
- to->si_signo = from.si_signo;
|
|
|
- to->si_errno = from.si_errno;
|
|
|
- to->si_code = from.si_code;
|
|
|
- switch(siginfo_layout(from.si_signo, from.si_code)) {
|
|
|
+ to->si_signo = from->si_signo;
|
|
|
+ to->si_errno = from->si_errno;
|
|
|
+ to->si_code = from->si_code;
|
|
|
+ switch(siginfo_layout(from->si_signo, from->si_code)) {
|
|
|
case SIL_KILL:
|
|
|
- to->si_pid = from.si_pid;
|
|
|
- to->si_uid = from.si_uid;
|
|
|
+ to->si_pid = from->si_pid;
|
|
|
+ to->si_uid = from->si_uid;
|
|
|
break;
|
|
|
case SIL_TIMER:
|
|
|
- to->si_tid = from.si_tid;
|
|
|
- to->si_overrun = from.si_overrun;
|
|
|
- to->si_int = from.si_int;
|
|
|
+ to->si_tid = from->si_tid;
|
|
|
+ to->si_overrun = from->si_overrun;
|
|
|
+ to->si_int = from->si_int;
|
|
|
break;
|
|
|
case SIL_POLL:
|
|
|
- to->si_band = from.si_band;
|
|
|
- to->si_fd = from.si_fd;
|
|
|
+ to->si_band = from->si_band;
|
|
|
+ to->si_fd = from->si_fd;
|
|
|
break;
|
|
|
case SIL_FAULT:
|
|
|
- to->si_addr = compat_ptr(from.si_addr);
|
|
|
+ to->si_addr = compat_ptr(from->si_addr);
|
|
|
#ifdef __ARCH_SI_TRAPNO
|
|
|
- to->si_trapno = from.si_trapno;
|
|
|
+ to->si_trapno = from->si_trapno;
|
|
|
#endif
|
|
|
break;
|
|
|
case SIL_FAULT_MCEERR:
|
|
|
- to->si_addr = compat_ptr(from.si_addr);
|
|
|
+ to->si_addr = compat_ptr(from->si_addr);
|
|
|
#ifdef __ARCH_SI_TRAPNO
|
|
|
- to->si_trapno = from.si_trapno;
|
|
|
+ to->si_trapno = from->si_trapno;
|
|
|
#endif
|
|
|
- to->si_addr_lsb = from.si_addr_lsb;
|
|
|
+ to->si_addr_lsb = from->si_addr_lsb;
|
|
|
break;
|
|
|
case SIL_FAULT_BNDERR:
|
|
|
- to->si_addr = compat_ptr(from.si_addr);
|
|
|
+ to->si_addr = compat_ptr(from->si_addr);
|
|
|
#ifdef __ARCH_SI_TRAPNO
|
|
|
- to->si_trapno = from.si_trapno;
|
|
|
+ to->si_trapno = from->si_trapno;
|
|
|
#endif
|
|
|
- to->si_lower = compat_ptr(from.si_lower);
|
|
|
- to->si_upper = compat_ptr(from.si_upper);
|
|
|
+ to->si_lower = compat_ptr(from->si_lower);
|
|
|
+ to->si_upper = compat_ptr(from->si_upper);
|
|
|
break;
|
|
|
case SIL_FAULT_PKUERR:
|
|
|
- to->si_addr = compat_ptr(from.si_addr);
|
|
|
+ to->si_addr = compat_ptr(from->si_addr);
|
|
|
#ifdef __ARCH_SI_TRAPNO
|
|
|
- to->si_trapno = from.si_trapno;
|
|
|
+ to->si_trapno = from->si_trapno;
|
|
|
#endif
|
|
|
- to->si_pkey = from.si_pkey;
|
|
|
+ to->si_pkey = from->si_pkey;
|
|
|
break;
|
|
|
case SIL_CHLD:
|
|
|
- to->si_pid = from.si_pid;
|
|
|
- to->si_uid = from.si_uid;
|
|
|
- to->si_status = from.si_status;
|
|
|
+ to->si_pid = from->si_pid;
|
|
|
+ to->si_uid = from->si_uid;
|
|
|
+ to->si_status = from->si_status;
|
|
|
#ifdef CONFIG_X86_X32_ABI
|
|
|
if (in_x32_syscall()) {
|
|
|
- to->si_utime = from._sifields._sigchld_x32._utime;
|
|
|
- to->si_stime = from._sifields._sigchld_x32._stime;
|
|
|
+ to->si_utime = from->_sifields._sigchld_x32._utime;
|
|
|
+ to->si_stime = from->_sifields._sigchld_x32._stime;
|
|
|
} else
|
|
|
#endif
|
|
|
{
|
|
|
- to->si_utime = from.si_utime;
|
|
|
- to->si_stime = from.si_stime;
|
|
|
+ to->si_utime = from->si_utime;
|
|
|
+ to->si_stime = from->si_stime;
|
|
|
}
|
|
|
break;
|
|
|
case SIL_RT:
|
|
|
- to->si_pid = from.si_pid;
|
|
|
- to->si_uid = from.si_uid;
|
|
|
- to->si_int = from.si_int;
|
|
|
+ to->si_pid = from->si_pid;
|
|
|
+ to->si_uid = from->si_uid;
|
|
|
+ to->si_int = from->si_int;
|
|
|
break;
|
|
|
case SIL_SYS:
|
|
|
- to->si_call_addr = compat_ptr(from.si_call_addr);
|
|
|
- to->si_syscall = from.si_syscall;
|
|
|
- to->si_arch = from.si_arch;
|
|
|
+ to->si_call_addr = compat_ptr(from->si_call_addr);
|
|
|
+ to->si_syscall = from->si_syscall;
|
|
|
+ to->si_arch = from->si_arch;
|
|
|
break;
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
+
|
|
|
+static int __copy_siginfo_from_user32(int signo, struct kernel_siginfo *to,
|
|
|
+ const struct compat_siginfo __user *ufrom)
|
|
|
+{
|
|
|
+ struct compat_siginfo from;
|
|
|
+
|
|
|
+ if (copy_from_user(&from, ufrom, sizeof(struct compat_siginfo)))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ from.si_signo = signo;
|
|
|
+ return post_copy_siginfo_from_user32(to, &from);
|
|
|
+}
|
|
|
+
|
|
|
+int copy_siginfo_from_user32(struct kernel_siginfo *to,
|
|
|
+ const struct compat_siginfo __user *ufrom)
|
|
|
+{
|
|
|
+ struct compat_siginfo from;
|
|
|
+
|
|
|
+ if (copy_from_user(&from, ufrom, sizeof(struct compat_siginfo)))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ return post_copy_siginfo_from_user32(to, &from);
|
|
|
+}
|
|
|
#endif /* CONFIG_COMPAT */
|
|
|
|
|
|
/**
|
|
@@ -3081,7 +3164,7 @@ int copy_siginfo_from_user32(struct siginfo *to,
|
|
|
* @info: if non-null, the signal's siginfo is returned here
|
|
|
* @ts: upper bound on process time suspension
|
|
|
*/
|
|
|
-static int do_sigtimedwait(const sigset_t *which, siginfo_t *info,
|
|
|
+static int do_sigtimedwait(const sigset_t *which, kernel_siginfo_t *info,
|
|
|
const struct timespec *ts)
|
|
|
{
|
|
|
ktime_t *to = NULL, timeout = KTIME_MAX;
|
|
@@ -3145,7 +3228,7 @@ SYSCALL_DEFINE4(rt_sigtimedwait, const sigset_t __user *, uthese,
|
|
|
{
|
|
|
sigset_t these;
|
|
|
struct timespec ts;
|
|
|
- siginfo_t info;
|
|
|
+ kernel_siginfo_t info;
|
|
|
int ret;
|
|
|
|
|
|
/* XXX: Don't preclude handling different sized sigset_t's. */
|
|
@@ -3177,7 +3260,7 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese,
|
|
|
{
|
|
|
sigset_t s;
|
|
|
struct timespec t;
|
|
|
- siginfo_t info;
|
|
|
+ kernel_siginfo_t info;
|
|
|
long ret;
|
|
|
|
|
|
if (sigsetsize != sizeof(sigset_t))
|
|
@@ -3209,7 +3292,7 @@ COMPAT_SYSCALL_DEFINE4(rt_sigtimedwait, compat_sigset_t __user *, uthese,
|
|
|
*/
|
|
|
SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)
|
|
|
{
|
|
|
- struct siginfo info;
|
|
|
+ struct kernel_siginfo info;
|
|
|
|
|
|
clear_siginfo(&info);
|
|
|
info.si_signo = sig;
|
|
@@ -3222,7 +3305,7 @@ SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)
|
|
|
}
|
|
|
|
|
|
static int
|
|
|
-do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info)
|
|
|
+do_send_specific(pid_t tgid, pid_t pid, int sig, struct kernel_siginfo *info)
|
|
|
{
|
|
|
struct task_struct *p;
|
|
|
int error = -ESRCH;
|
|
@@ -3253,7 +3336,7 @@ do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info)
|
|
|
|
|
|
static int do_tkill(pid_t tgid, pid_t pid, int sig)
|
|
|
{
|
|
|
- struct siginfo info;
|
|
|
+ struct kernel_siginfo info;
|
|
|
|
|
|
clear_siginfo(&info);
|
|
|
info.si_signo = sig;
|
|
@@ -3300,7 +3383,7 @@ SYSCALL_DEFINE2(tkill, pid_t, pid, int, sig)
|
|
|
return do_tkill(0, pid, sig);
|
|
|
}
|
|
|
|
|
|
-static int do_rt_sigqueueinfo(pid_t pid, int sig, siginfo_t *info)
|
|
|
+static int do_rt_sigqueueinfo(pid_t pid, int sig, kernel_siginfo_t *info)
|
|
|
{
|
|
|
/* Not even root can pretend to send signals from the kernel.
|
|
|
* Nor can they impersonate a kill()/tgkill(), which adds source info.
|
|
@@ -3309,8 +3392,6 @@ static int do_rt_sigqueueinfo(pid_t pid, int sig, siginfo_t *info)
|
|
|
(task_pid_vnr(current) != pid))
|
|
|
return -EPERM;
|
|
|
|
|
|
- info->si_signo = sig;
|
|
|
-
|
|
|
/* POSIX.1b doesn't mention process groups. */
|
|
|
return kill_proc_info(sig, info, pid);
|
|
|
}
|
|
@@ -3324,9 +3405,10 @@ static int do_rt_sigqueueinfo(pid_t pid, int sig, siginfo_t *info)
|
|
|
SYSCALL_DEFINE3(rt_sigqueueinfo, pid_t, pid, int, sig,
|
|
|
siginfo_t __user *, uinfo)
|
|
|
{
|
|
|
- siginfo_t info;
|
|
|
- if (copy_from_user(&info, uinfo, sizeof(siginfo_t)))
|
|
|
- return -EFAULT;
|
|
|
+ kernel_siginfo_t info;
|
|
|
+ int ret = __copy_siginfo_from_user(sig, &info, uinfo);
|
|
|
+ if (unlikely(ret))
|
|
|
+ return ret;
|
|
|
return do_rt_sigqueueinfo(pid, sig, &info);
|
|
|
}
|
|
|
|
|
@@ -3336,15 +3418,15 @@ COMPAT_SYSCALL_DEFINE3(rt_sigqueueinfo,
|
|
|
int, sig,
|
|
|
struct compat_siginfo __user *, uinfo)
|
|
|
{
|
|
|
- siginfo_t info;
|
|
|
- int ret = copy_siginfo_from_user32(&info, uinfo);
|
|
|
+ kernel_siginfo_t info;
|
|
|
+ int ret = __copy_siginfo_from_user32(sig, &info, uinfo);
|
|
|
if (unlikely(ret))
|
|
|
return ret;
|
|
|
return do_rt_sigqueueinfo(pid, sig, &info);
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
-static int do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, siginfo_t *info)
|
|
|
+static int do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, kernel_siginfo_t *info)
|
|
|
{
|
|
|
/* This is only valid for single tasks */
|
|
|
if (pid <= 0 || tgid <= 0)
|
|
@@ -3357,19 +3439,16 @@ static int do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, siginfo_t *info)
|
|
|
(task_pid_vnr(current) != pid))
|
|
|
return -EPERM;
|
|
|
|
|
|
- info->si_signo = sig;
|
|
|
-
|
|
|
return do_send_specific(tgid, pid, sig, info);
|
|
|
}
|
|
|
|
|
|
SYSCALL_DEFINE4(rt_tgsigqueueinfo, pid_t, tgid, pid_t, pid, int, sig,
|
|
|
siginfo_t __user *, uinfo)
|
|
|
{
|
|
|
- siginfo_t info;
|
|
|
-
|
|
|
- if (copy_from_user(&info, uinfo, sizeof(siginfo_t)))
|
|
|
- return -EFAULT;
|
|
|
-
|
|
|
+ kernel_siginfo_t info;
|
|
|
+ int ret = __copy_siginfo_from_user(sig, &info, uinfo);
|
|
|
+ if (unlikely(ret))
|
|
|
+ return ret;
|
|
|
return do_rt_tgsigqueueinfo(tgid, pid, sig, &info);
|
|
|
}
|
|
|
|
|
@@ -3380,10 +3459,10 @@ COMPAT_SYSCALL_DEFINE4(rt_tgsigqueueinfo,
|
|
|
int, sig,
|
|
|
struct compat_siginfo __user *, uinfo)
|
|
|
{
|
|
|
- siginfo_t info;
|
|
|
-
|
|
|
- if (copy_siginfo_from_user32(&info, uinfo))
|
|
|
- return -EFAULT;
|
|
|
+ kernel_siginfo_t info;
|
|
|
+ int ret = __copy_siginfo_from_user32(sig, &info, uinfo);
|
|
|
+ if (unlikely(ret))
|
|
|
+ return ret;
|
|
|
return do_rt_tgsigqueueinfo(tgid, pid, sig, &info);
|
|
|
}
|
|
|
#endif
|
|
@@ -3966,13 +4045,57 @@ __weak const char *arch_vma_name(struct vm_area_struct *vma)
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
-void __init signals_init(void)
|
|
|
+static inline void siginfo_buildtime_checks(void)
|
|
|
{
|
|
|
- /* If this check fails, the __ARCH_SI_PREAMBLE_SIZE value is wrong! */
|
|
|
- BUILD_BUG_ON(__ARCH_SI_PREAMBLE_SIZE
|
|
|
- != offsetof(struct siginfo, _sifields._pad));
|
|
|
BUILD_BUG_ON(sizeof(struct siginfo) != SI_MAX_SIZE);
|
|
|
|
|
|
+ /* Verify the offsets in the two siginfos match */
|
|
|
+#define CHECK_OFFSET(field) \
|
|
|
+ BUILD_BUG_ON(offsetof(siginfo_t, field) != offsetof(kernel_siginfo_t, field))
|
|
|
+
|
|
|
+ /* kill */
|
|
|
+ CHECK_OFFSET(si_pid);
|
|
|
+ CHECK_OFFSET(si_uid);
|
|
|
+
|
|
|
+ /* timer */
|
|
|
+ CHECK_OFFSET(si_tid);
|
|
|
+ CHECK_OFFSET(si_overrun);
|
|
|
+ CHECK_OFFSET(si_value);
|
|
|
+
|
|
|
+ /* rt */
|
|
|
+ CHECK_OFFSET(si_pid);
|
|
|
+ CHECK_OFFSET(si_uid);
|
|
|
+ CHECK_OFFSET(si_value);
|
|
|
+
|
|
|
+ /* sigchld */
|
|
|
+ CHECK_OFFSET(si_pid);
|
|
|
+ CHECK_OFFSET(si_uid);
|
|
|
+ CHECK_OFFSET(si_status);
|
|
|
+ CHECK_OFFSET(si_utime);
|
|
|
+ CHECK_OFFSET(si_stime);
|
|
|
+
|
|
|
+ /* sigfault */
|
|
|
+ CHECK_OFFSET(si_addr);
|
|
|
+ CHECK_OFFSET(si_addr_lsb);
|
|
|
+ CHECK_OFFSET(si_lower);
|
|
|
+ CHECK_OFFSET(si_upper);
|
|
|
+ CHECK_OFFSET(si_pkey);
|
|
|
+
|
|
|
+ /* sigpoll */
|
|
|
+ CHECK_OFFSET(si_band);
|
|
|
+ CHECK_OFFSET(si_fd);
|
|
|
+
|
|
|
+ /* sigsys */
|
|
|
+ CHECK_OFFSET(si_call_addr);
|
|
|
+ CHECK_OFFSET(si_syscall);
|
|
|
+ CHECK_OFFSET(si_arch);
|
|
|
+#undef CHECK_OFFSET
|
|
|
+}
|
|
|
+
|
|
|
+void __init signals_init(void)
|
|
|
+{
|
|
|
+ siginfo_buildtime_checks();
|
|
|
+
|
|
|
sigqueue_cachep = KMEM_CACHE(sigqueue, SLAB_PANIC);
|
|
|
}
|
|
|
|