[PATCH 5/6] tty/sysrq: Add configurable handler to signal a process

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Some userland might want to implement a policy to signal a configured
process with a configured signal. This patch adds necessary kernel-side
infrastructure and the newly added handler is triggered with
Alt-Shift-SysRq-s. Optionally the userland can also specify the expected
name of parent process of the victim.

Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@xxxxxxxxxxxxx>
---
 drivers/tty/sysrq.c | 123 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 122 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index ab4121a446b4..a6e91e4ae304 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -437,6 +437,15 @@ static struct sysrq_key_op sysrq_unrt_op = {
 	.enable_mask	= SYSRQ_ENABLE_RTNICE,
 };
 
+static void sysrq_signal_configured(int key);
+
+static struct sysrq_key_op sysrq_signal_configured_op = {
+	.handler	= sysrq_signal_configured,
+	.help_msg	= "signal-configured-process(S)",
+	.action_msg	= "Signal configured process",
+	.enable_mask	= SYSRQ_ENABLE_SIGNAL,
+};
+
 /* Key Operations table and lock */
 static DEFINE_SPINLOCK(sysrq_key_table_lock);
 
@@ -515,7 +524,7 @@ static struct sysrq_key_op *sysrq_key_table[62] = {
 	NULL,				/* P */
 	NULL,				/* Q */
 	NULL,				/* R */
-	NULL,				/* S */
+	&sysrq_signal_configured_op,	/* S */
 	NULL,				/* T */
 	NULL,				/* U */
 	NULL,				/* V */
@@ -633,6 +642,10 @@ EXPORT_SYMBOL(handle_sysrq);
 #ifdef CONFIG_INPUT
 static int sysrq_reset_downtime_ms;
 static unsigned short sysrq_key = KEY_SYSRQ;
+static char *sysrq_signalled;
+static char *sysrq_signalled_parent;
+static char *sysrq_signal;
+static int sysrq_signal_code;
 
 /* Simple translation table for the SysRq keys */
 static const unsigned char sysrq_xlate[KEY_CNT] =
@@ -751,6 +764,106 @@ static void sysrq_detect_reset_sequence(struct sysrq_state *state,
 	}
 }
 
+struct signal_search {
+	const char *name;
+	int code;
+};
+
+static void sysrq_str_to_signal(void)
+{
+	static const struct signal_search signals[] = {
+		{"SIGHUP", SIGHUP},
+		{"SIGINT", SIGINT},
+		{"SIGQUIT", SIGQUIT},
+		{"SIGILL", SIGILL},
+		{"SIGTRAP", SIGTRAP},
+		{"SIGABRT", SIGABRT},
+		{"SIGIOT", SIGIOT},
+		{"SIGBUS", SIGBUS},
+		{"SIGFPE", SIGFPE},
+		{"SIGKILL", SIGKILL},
+		{"SIGUSR1", SIGUSR1},
+		{"SIGSEGV", SIGSEGV},
+		{"SIGUSR2", SIGUSR2},
+		{"SIGPIPE", SIGPIPE},
+		{"SIGALRM", SIGALRM},
+		{"SIGTERM", SIGTERM},
+		{"SIGSTKFLT", SIGSTKFLT},
+		{"SIGCHLD", SIGCHLD},
+		{"SIGCONT", SIGCONT},
+		{"SIGSTOP", SIGSTOP},
+		{"SIGTSTP", SIGTSTP},
+		{"SIGTTIN", SIGTTIN},
+		{"SIGTTOU", SIGTTOU},
+		{"SIGURG", SIGURG},
+		{"SIGXCPU", SIGXCPU},
+		{"SIGXFSZ", SIGXFSZ},
+		{"SIGVTALRM", SIGVTALRM},
+		{"SIGPROF", SIGPROF},
+		{"SIGWINCH", SIGWINCH},
+		{"SIGIO", SIGIO},
+		{"SIGPOLL", SIGPOLL},
+		{"SIGPWR", SIGPWR},
+		{"SIGSYS", SIGSYS},
+	};
+	int i;
+
+	if (!sysrq_signal)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(signals); ++i)
+		if (!strcmp(signals[i].name, sysrq_signal))
+			break;
+
+	if (i >= ARRAY_SIZE(signals)) {
+		pr_err("Unknown signal name %s", sysrq_signal);
+
+		return;
+	}
+
+	sysrq_signal_code = signals[i].code;
+}
+
+static void sysrq_signal_configured(int key)
+{
+	struct task_struct *p;
+
+	sysrq_str_to_signal();
+
+	if (!sysrq_signalled) {
+		pr_err("Unconfigured process name for %s",
+		       sysrq_signal_configured_op.help_msg);
+
+		return;
+	}
+
+	if (!sysrq_signal_code) {
+		pr_err("Unconfigured signal for %s",
+		       sysrq_signal_configured_op.help_msg);
+
+		return;
+	}
+
+	read_lock(&tasklist_lock);
+	for_each_process(p) {
+		if (p->flags & (PF_KTHREAD | PF_EXITING))
+			continue;
+		if (is_global_init(p))
+			continue;
+		if (strncmp(p->comm, sysrq_signalled, TASK_COMM_LEN))
+			continue;
+		if (sysrq_signalled_parent
+		    && strncmp(p->parent->comm, sysrq_signalled_parent,
+			       TASK_COMM_LEN))
+			continue;
+
+		pr_err("%s: signal %d %s pid %u tgid %u\n", __func__,
+		       sysrq_signal_code, sysrq_signalled, p->pid, p->tgid);
+		do_send_sig_info(sysrq_signal_code, SEND_SIG_PRIV, p, true);
+	}
+	read_unlock(&tasklist_lock);
+}
+
 
 static void sysrq_reinject_alt_sysrq(struct work_struct *work)
 {
@@ -1048,8 +1161,16 @@ module_param_named(sysrq_downtime_ms, sysrq_reset_downtime_ms, int, 0644);
 
 module_param(sysrq_key, ushort, 0644);
 
+module_param(sysrq_signalled, charp, 0644);
+module_param(sysrq_signalled_parent, charp, 0644);
+module_param(sysrq_signal, charp, 0644);
+
 #else
 
+static void sysrq_signal_configured(int key)
+{
+}
+
 static inline void sysrq_register_handler(void)
 {
 }
-- 
2.17.1




[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux