[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20110621130040.12035.62533.sendpatchset@prarit.bos.redhat.com>
Date: Tue, 21 Jun 2011 09:00:40 -0400
From: Prarit Bhargava <prarit@...hat.com>
To: netdev@...r.kernel.org, davem@...emloft.net, agospoda@...hat.com,
nhorman@...hat.com, lwoodman@...hat.com
Cc: Prarit Bhargava <prarit@...hat.com>
Subject: [PATCH]: Add Network Sysrq Support
Add Network Sysrq Support
In some circumstances, a system can hang/lockup in such a way that the system
is completely unresponsive to keyboard or console input but is still
responsive to ping. The config option, CONFIG_SYSRQ_PING, builds
net/ipv4/sysrq-ping.ko which allows a root user to configure the system for
a remote sysrq.
To use this do:
mount -t debugfs none /sys/kernel/debug/
echo 1 > /proc/sys/kernel/sysrq
echo <hex digit val> > /sys/kernel/debug/network_sysrq_magic
echo 1 > /sys/kernel/debug/network_sysrq_enable
Then on another system on the network you can do:
ping -c 1 -p <up to 30 hex digit val><hex val of sysrq> <target_system_name>
ex) sysrq-m, m is ascii 0x6d
ping -c 1 p 1623a06f554d46d676d <target_system_name>
Note that the network sysrq automatically disables after the receipt of
the ping, ie) it is single-shot mode. If you want to use this again, you
must complete the above four steps again.
Signed-off-by: Prarit Bhargava <prarit@...hat.com>
diff --git a/Documentation/networking/sysrq-ping.txt b/Documentation/networking/sysrq-ping.txt
new file mode 100644
index 0000000..efa8be3
--- /dev/null
+++ b/Documentation/networking/sysrq-ping.txt
@@ -0,0 +1,26 @@
+In some circumstances, a system can hang/lockup in such a way that the system
+is completely unresponsive to keyboard or console input but is still
+responsive to ping. The config option, CONFIG_SYSRQ_PING, builds
+net/ipv4/sysrq-ping.ko which allows a root user to configure the system for a
+remote sysrq.
+
+To use this do:
+
+mount -t debugfs none /sys/kernel/debug/
+echo 1 > /proc/sys/kernel/sysrq
+echo <hex digit val> > /sys/kernel/debug/network_sysrq_magic
+echo 1 > /sys/kernel/debug/network_sysrq_enable
+
+Then on another system you can do:
+
+ping -c 1 -p <hex digit val><hex val of sysrq> <target_system_name>
+
+ex) sysrq-m, m is ascii 0x6d
+
+ ping -c 1 p 1623a06f554d46d676d <target_system_name>
+
+Note that the network sysrq automatically disables after the receipt of
+the ping, ie) it is single-shot mode. If you want to use this again, you
+must complete the above four steps again.
+
+Hint: 'man ascii' ;)
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index cbb505b..03bb7b1 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -624,3 +624,11 @@ config TCP_MD5SIG
on the Internet.
If unsure, say N.
+
+config SYSRQ_PING
+ tristate
+ default m
+ help
+ Allows execution of sysrq-X commands via ping over ipv4. This is a
+ known security hazard and should not be used in unsecure
+ environments.
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index f2dc69c..c23c15e 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_TCP_CONG_LP) += tcp_lp.o
obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o
obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o
obj-$(CONFIG_NETLABEL) += cipso_ipv4.o
+obj-$(CONFIG_SYSRQ_PING) += sysrq-ping.o
obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \
xfrm4_output.o
diff --git a/net/ipv4/sysrq-ping.c b/net/ipv4/sysrq-ping.c
new file mode 100644
index 0000000..67a6d0e
--- /dev/null
+++ b/net/ipv4/sysrq-ping.c
@@ -0,0 +1,207 @@
+/*
+ * network_sysrq.c - allow sysrq to be executed over a network via ping
+ *
+ * written by: Prarit Bhargava <prarit@...hat.com>
+ * Andy Gospodarek <agospoda@...hat.com>
+ * Neil Horman <nhorman@...hat.com>
+ *
+ * based on work by: Larry Woodman <lwoodman@...hat.com>
+ *
+ * To use this do:
+ *
+ * mount -t debugfs none /sys/kernel/debug/
+ * echo 1 > /proc/sys/kernel/sysrq
+ * echo <hex digit val> > /sys/kernel/debug/network_sysrq_magic
+ * echo 1 > /sys/kernel/debug/network_sysrq_enable
+ *
+ * Then on another system you can do:
+ *
+ * ping -c 1 -p <hex digit val><hex val of sysrq> <target_system_name>
+ *
+ * ex) sysrq-m, m is 0x6d
+ *
+ * ping -c 1 p 1623a06f554d46d676d <target_system_name>
+ *
+ * Note that the network sysrq automatically disables after the receipt of
+ * *ANY* ping. If you want to use this again, you must complete the
+ * above four steps again.
+ *
+ */
+
+#include <linux/debugfs.h>
+#include <linux/icmp.h>
+#include <linux/init.h>
+#include <linux/ip.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/sysrq.h>
+
+#include <net/xfrm.h>
+
+static u8 network_sysrq_enable; /* set in debugfs network_sysrq_enable */
+static u16 network_sysrq_magic[16]; /* 15 bytes leaves 1 feature byte */
+static int network_sysrq_magic_len;
+
+static int to_hex(int val)
+{
+ if ((val >= '0') && (val <= '9'))
+ return val - 0x30;
+
+ if ((val >= 'a') && (val <= 'f'))
+ return val - 0x37;
+
+ if ((val >= 'A') && (val <= 'F'))
+ return val - 0x57;
+
+ return -1;
+}
+
+static bool network_sysrq_armed(void)
+{
+ int i;
+
+ if (!network_sysrq_enable)
+ return false;
+ if (!network_sysrq_magic_len)
+ return false;
+ for (i = 0; i < 16; i++)
+ if (network_sysrq_magic[i] != 0)
+ return true;
+ return false;
+}
+
+static void network_sysrq_disable(void)
+{
+ network_sysrq_enable = 0;
+ memset(network_sysrq_magic, 0, 32);
+ network_sysrq_magic_len = 0;
+}
+
+static ssize_t network_sysrq_seq_write(struct file *file,
+ const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ int i, j, hi, lo;
+ char buf[33];
+ memset(buf, 0, sizeof(buf));
+
+ if (count >= 33)
+ return -EINVAL;
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ for (i = 0, j = 0; i < count - 2 ; i += 2, j++) {
+ hi = to_hex(buf[i]);
+ lo = to_hex(buf[i+1]) & 0x0f;
+ if ((hi == -1) || (lo == -1)) {
+ network_sysrq_disable();
+ return -EINVAL;
+ }
+ network_sysrq_magic[j] = (u16)(hi << 4) + lo;
+ }
+ network_sysrq_magic_len = j;
+
+ return count;
+}
+
+static int network_sysrq_seq_show(struct seq_file *m, void *p)
+{
+ int i;
+
+ for (i = 0; i < network_sysrq_magic_len; i++)
+ seq_printf(m, "%02x", network_sysrq_magic[i]);
+ seq_printf(m, "\n");
+ return 0;
+}
+
+static int network_sysrq_fops_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, network_sysrq_seq_show, inode->i_private);
+}
+
+static const struct file_operations xnetwork_sysrq_fops = {
+ .open = network_sysrq_fops_open,
+ .write = network_sysrq_seq_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+};
+
+static int network_sysrq_func(struct sk_buff *skb, struct net_device *dev,
+ struct packet_type *pt,
+ struct net_device *orig_dev)
+{
+ struct icmphdr *icmph;
+ char *found;
+
+ if (ip_hdr(skb)->protocol != IPPROTO_ICMP)
+ goto end;
+
+ if (!skb_pull(skb, sizeof(struct iphdr)))
+ goto end;
+
+ skb_reset_transport_header(skb);
+ icmph = icmp_hdr(skb);
+
+ if (!skb_pull(skb, sizeof(*icmph)))
+ goto end;
+
+ /* is this a ping? */
+ if (icmph->type != ICMP_ECHO)
+ goto end;
+
+ if (network_sysrq_armed()) {
+ found = strnstr(skb->data, (char *)network_sysrq_magic,
+ skb->len - skb->data_len);
+ if (found)
+ handle_sysrq(found[network_sysrq_magic_len]);
+ network_sysrq_disable();
+ }
+end:
+ kfree_skb(skb);
+ return 0;
+}
+
+static struct packet_type network_sysrq_type = {
+ .type = cpu_to_be16(ETH_P_IP),
+ .func = network_sysrq_func,
+};
+
+static struct dentry *network_sysrq_enable_dentry;
+static struct dentry *network_sysrq_magic_dentry;
+
+int __init init_network_sysrq(void)
+{
+ network_sysrq_enable_dentry = debugfs_create_u8("network_sysrq_enable",
+ S_IWUGO | S_IRUGO,
+ NULL,
+ &network_sysrq_enable);
+ if (!network_sysrq_enable_dentry)
+ return -EIO;
+
+ network_sysrq_magic_dentry = debugfs_create_file("network_sysrq_magic",
+ S_IWUGO | S_IRUGO,
+ NULL,
+ &network_sysrq_magic,
+ &xnetwork_sysrq_fops);
+ if (!network_sysrq_magic_dentry) {
+ debugfs_remove(network_sysrq_enable_dentry);
+ return -EIO;
+ }
+
+ dev_add_pack(&network_sysrq_type);
+ return 0;
+}
+
+void __exit cleanup_network_sysrq(void)
+{
+ dev_remove_pack(&network_sysrq_type);
+ debugfs_remove(network_sysrq_enable_dentry);
+ debugfs_remove(network_sysrq_magic_dentry);
+}
+
+module_init(init_network_sysrq);
+module_exit(cleanup_network_sysrq);
+
+MODULE_LICENSE("GPL");
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists