[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <4E0115B3.2030802@redhat.com>
Date: Tue, 21 Jun 2011 19:05:39 -0300
From: Flavio Leitner <fbl@...hat.com>
To: Prarit Bhargava <prarit@...hat.com>
CC: netdev@...r.kernel.org, davem@...emloft.net, agospoda@...hat.com,
nhorman@...hat.com, lwoodman@...hat.com
Subject: Re: [PATCH]: Add Network Sysrq Support
On 06/21/2011 10:00 AM, Prarit Bhargava wrote:
> 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>
missing '-' in front of 'p'
>
> 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>
again -p
> +
> +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
prompt?
> + 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>
again -p
> + *
> + * 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.
why not leave it running? perhaps disable it for some time to
filter any ping retransmission, for instance netsysrq_reenable=10 seconds.
and then do if (time_after(jiffies, last_ping + netsysrq_reenable))...
I have an USB KVM console, so often when testing workload, the USB takes
ages to register the keyboard and I'd like to shot some sysrq+t or w,
so if it disables after the first one, I can't get more traces because
I simply can't enable it 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;
What about a whitelist of source MAC or IP addresses to accept the sysrq?
I'm thinking on a situation where we leave the systems with this enabled
and then an ordinary user starts pinging the network guessing the hexa to
cause reboots.
Tested here and it works.
Tested-by: Flavio Leitner <fbl@...hat.com>
fbl
> + 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
>
--
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