signal: Simplify and fix kdb_send_sig
- Rename from kdb_send_sig_info to kdb_send_sig As there is no meaningful siginfo sent - Use SEND_SIG_PRIV instead of generating a siginfo for a kdb signal. The generated siginfo had a bogus rationale and was not correct in the face of pid namespaces. SEND_SIG_PRIV is simpler and actually correct. - As the code grabs siglock just send the signal with siglock held instead of dropping siglock and attempting to grab it again. - Move the sig_valid test into kdb_kill where it can generate a good error message. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
This commit is contained in:
parent
30a7acd573
commit
0b44bf9a6f
|
@ -2441,7 +2441,6 @@ static int kdb_kill(int argc, const char **argv)
|
||||||
long sig, pid;
|
long sig, pid;
|
||||||
char *endp;
|
char *endp;
|
||||||
struct task_struct *p;
|
struct task_struct *p;
|
||||||
struct siginfo info;
|
|
||||||
|
|
||||||
if (argc != 2)
|
if (argc != 2)
|
||||||
return KDB_ARGCOUNT;
|
return KDB_ARGCOUNT;
|
||||||
|
@ -2449,7 +2448,7 @@ static int kdb_kill(int argc, const char **argv)
|
||||||
sig = simple_strtol(argv[1], &endp, 0);
|
sig = simple_strtol(argv[1], &endp, 0);
|
||||||
if (*endp)
|
if (*endp)
|
||||||
return KDB_BADINT;
|
return KDB_BADINT;
|
||||||
if (sig >= 0) {
|
if ((sig >= 0) || !valid_signal(-sig)) {
|
||||||
kdb_printf("Invalid signal parameter.<-signal>\n");
|
kdb_printf("Invalid signal parameter.<-signal>\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2470,12 +2469,7 @@ static int kdb_kill(int argc, const char **argv)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
p = p->group_leader;
|
p = p->group_leader;
|
||||||
info.si_signo = sig;
|
kdb_send_sig(p, sig);
|
||||||
info.si_errno = 0;
|
|
||||||
info.si_code = SI_USER;
|
|
||||||
info.si_pid = pid; /* same capabilities as process being signalled */
|
|
||||||
info.si_uid = 0; /* kdb has root authority */
|
|
||||||
kdb_send_sig_info(p, &info);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -208,7 +208,7 @@ extern unsigned long kdb_task_state(const struct task_struct *p,
|
||||||
extern void kdb_ps_suppressed(void);
|
extern void kdb_ps_suppressed(void);
|
||||||
extern void kdb_ps1(const struct task_struct *p);
|
extern void kdb_ps1(const struct task_struct *p);
|
||||||
extern void kdb_print_nameval(const char *name, unsigned long val);
|
extern void kdb_print_nameval(const char *name, unsigned long val);
|
||||||
extern void kdb_send_sig_info(struct task_struct *p, struct siginfo *info);
|
extern void kdb_send_sig(struct task_struct *p, int sig);
|
||||||
extern void kdb_meminfo_proc_show(void);
|
extern void kdb_meminfo_proc_show(void);
|
||||||
extern char *kdb_getstr(char *, size_t, const char *);
|
extern char *kdb_getstr(char *, size_t, const char *);
|
||||||
extern void kdb_gdb_state_pass(char *buf);
|
extern void kdb_gdb_state_pass(char *buf);
|
||||||
|
|
|
@ -3684,26 +3684,25 @@ void __init signals_init(void)
|
||||||
#ifdef CONFIG_KGDB_KDB
|
#ifdef CONFIG_KGDB_KDB
|
||||||
#include <linux/kdb.h>
|
#include <linux/kdb.h>
|
||||||
/*
|
/*
|
||||||
* kdb_send_sig_info - Allows kdb to send signals without exposing
|
* kdb_send_sig - Allows kdb to send signals without exposing
|
||||||
* signal internals. This function checks if the required locks are
|
* signal internals. This function checks if the required locks are
|
||||||
* available before calling the main signal code, to avoid kdb
|
* available before calling the main signal code, to avoid kdb
|
||||||
* deadlocks.
|
* deadlocks.
|
||||||
*/
|
*/
|
||||||
void
|
void kdb_send_sig(struct task_struct *t, int sig)
|
||||||
kdb_send_sig_info(struct task_struct *t, struct siginfo *info)
|
|
||||||
{
|
{
|
||||||
static struct task_struct *kdb_prev_t;
|
static struct task_struct *kdb_prev_t;
|
||||||
int sig, new_t;
|
int new_t, ret;
|
||||||
if (!spin_trylock(&t->sighand->siglock)) {
|
if (!spin_trylock(&t->sighand->siglock)) {
|
||||||
kdb_printf("Can't do kill command now.\n"
|
kdb_printf("Can't do kill command now.\n"
|
||||||
"The sigmask lock is held somewhere else in "
|
"The sigmask lock is held somewhere else in "
|
||||||
"kernel, try again later\n");
|
"kernel, try again later\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
spin_unlock(&t->sighand->siglock);
|
|
||||||
new_t = kdb_prev_t != t;
|
new_t = kdb_prev_t != t;
|
||||||
kdb_prev_t = t;
|
kdb_prev_t = t;
|
||||||
if (t->state != TASK_RUNNING && new_t) {
|
if (t->state != TASK_RUNNING && new_t) {
|
||||||
|
spin_unlock(&t->sighand->siglock);
|
||||||
kdb_printf("Process is not RUNNING, sending a signal from "
|
kdb_printf("Process is not RUNNING, sending a signal from "
|
||||||
"kdb risks deadlock\n"
|
"kdb risks deadlock\n"
|
||||||
"on the run queue locks. "
|
"on the run queue locks. "
|
||||||
|
@ -3712,8 +3711,9 @@ kdb_send_sig_info(struct task_struct *t, struct siginfo *info)
|
||||||
"the deadlock.\n");
|
"the deadlock.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sig = info->si_signo;
|
ret = send_signal(sig, SEND_SIG_PRIV, t, false);
|
||||||
if (send_sig_info(sig, info, t))
|
spin_unlock(&t->sighand->siglock);
|
||||||
|
if (ret)
|
||||||
kdb_printf("Fail to deliver Signal %d to process %d.\n",
|
kdb_printf("Fail to deliver Signal %d to process %d.\n",
|
||||||
sig, t->pid);
|
sig, t->pid);
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in New Issue