FreeBSD-10.3-ipod.patch 4.05 KB
Newer Older
Mike Hibler's avatar
Mike Hibler committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
#
# Utah kernel modification to allow an authenticated ICMP "Ping Of Death"
# ("ipod") packet. (Yes, we came before that other ipod...) We only define
# this on node kernels and not on the servers.
#
#   cd /usr/src
#   sudo patch -p0 < patchfile
#

diff -rNu sys.orig/conf/options sys/conf/options
--- sys.orig/conf/options	2017-03-28 17:06:47.354763000 -0600
+++ sys/conf/options	2016-05-27 09:49:40.000000000 -0600
@@ -941,3 +941,6 @@
 
 # Intel em(4) driver
 EM_MULTIQUEUE	opt_em.h
+
+# Emulab Ping of Death
+ICMP_PINGOFDEATH	opt_icmp_pingofdeath.h
diff -rNu sys.orig/netinet/ip_icmp.c sys/netinet/ip_icmp.c
--- sys.orig/netinet/ip_icmp.c	2017-03-28 17:07:36.048265000 -0600
+++ sys/netinet/ip_icmp.c	2016-05-27 10:33:19.000000000 -0600
@@ -155,6 +155,11 @@
 static void	icmp_reflect(struct mbuf *);
 static void	icmp_send(struct mbuf *, struct mbuf *);
 
+#include "opt_icmp_pingofdeath.h"
+#ifdef ICMP_PINGOFDEATH
+static void icmp_pingofdeath(struct icmp *, struct ip *, int);
+#endif
+
 extern	struct protosw inetsw[];
 
 static int
@@ -661,6 +666,12 @@
 		pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc);
 		break;
 
+#ifdef ICMP_PINGOFDEATH
+	case ICMP_PINGOFDEATH:
+		icmp_pingofdeath(icp, ip, hlen);
+		break;
+#endif
+
 	/*
 	 * No kernel processing for the following;
 	 * just fall through to send to raw listener.
@@ -1006,3 +1017,114 @@
 	return 0;			/* okay to send packet */
 #undef N
 }
+
+#ifdef ICMP_PINGOFDEATH
+#include <sys/proc.h>
+#include <sys/sched.h>
+#include <sys/syslog.h>
+
+SYSCTL_NODE(_net_inet_icmp, OID_AUTO, ipod, CTLFLAG_RW, 0,
+	"ICMP Ping of Death");
+
+/* non-virtualized */
+static int ipod_version = 2;
+SYSCTL_INT(_net_inet_icmp_ipod, OID_AUTO, version, CTLFLAG_RD,
+	&ipod_version, 0, "");
+
+static int ipod_enabled = 0;
+SYSCTL_INT(_net_inet_icmp_ipod, OID_AUTO, enabled, CTLFLAG_RW,
+	&ipod_enabled, 0, "");
+
+static unsigned long ipod_host = 0xffffffff;
+SYSCTL_ULONG(_net_inet_icmp_ipod, OID_AUTO, host, CTLFLAG_RW,
+	&ipod_host, 0, "");
+static unsigned long ipod_mask = 0xffffffff;
+SYSCTL_ULONG(_net_inet_icmp_ipod, OID_AUTO, mask, CTLFLAG_RW,
+	&ipod_mask, 0, "");
+
+static char ipod_key[32+1] = { "SETMETOSOMETHINGTHIRTYTWOBYTES!!" };
+#define IPOD_CHECK_KEY \
+	(ipod_key[0] != 0)
+#define IPOD_VALID_KEY(d) \
+	(strncmp(ipod_key, (char *)(d), strlen(ipod_key)) == 0)
+
+static int
+ipod_getkey(SYSCTL_HANDLER_ARGS)
+{
+	int error;
+
+	/* XXX fake up a result */
+	error = SYSCTL_OUT(req, "XXXX", 4+1);
+	if (error || !req->newptr)
+		return (error);
+
+	if ((req->newlen - req->newidx) >= sizeof(ipod_key))
+		return (EINVAL);
+
+	arg2 = (req->newlen - req->newidx);
+	error = SYSCTL_IN(req, ipod_key, arg2);
+	memset(&ipod_key[arg2], 0, sizeof(ipod_key) - arg2);
+
+	return (error);
+}
+
+SYSCTL_PROC(_net_inet_icmp_ipod, OID_AUTO, key, CTLTYPE_STRING | CTLFLAG_RW,
+	NULL, 0, ipod_getkey, "A", "");
+
+static void
+icmp_pingofdeath(icp, ip, hlen)
+	struct icmp *icp;
+	struct ip *ip;
+	int hlen;
+{
+	int doit = 0;
+
+	/*
+	 * If IPOD not enabled or wrong ICMP code, ignore.
+	 */
+	if (!ipod_enabled || icp->icmp_code != 6)
+		return;
+
+	/*
+	 * First check the source address info.
+	 * If host not set, ignore.
+	 */
+	if (ipod_host != 0xffffffff &&
+	    (ntohl(ip->ip_src.s_addr) & ipod_mask) == ipod_host) {
+		/*
+		 * Now check the key if enabled.
+		 * If packet doesn't contain enough data or key
+		 * is otherwise invalid, ignore.
+		 */
+		if (IPOD_CHECK_KEY) {
+			if (ntohs(ip->ip_len) >= strlen(ipod_key) &&
+			    IPOD_VALID_KEY(icp->icmp_data))
+				doit = 1;
+		} else {
+			doit = 1;
+		}
+	}
+
+	if (doit) {
+		ipod_enabled = 0;
+#if defined(SMP)
+		/*
+		 * Bind us to CPU 0 so that all shutdown code runs there.  Some
+		 * systems don't shutdown properly (i.e., ACPI power off) if we
+		 * run on another processor.
+		 */
+		thread_lock(curthread);
+		sched_bind(curthread, 0);
+		thread_unlock(curthread);
+#endif
+		splhigh();
+		printf("IPOD: reboot forced by %x...\n",
+		       ntohl(ip->ip_src.s_addr));
+		DELAY(1000000);
+		cpu_reset();
+	} else {
+		log(LOG_ERR, "IPOD: from %x rejected\n",
+		    ntohl(ip->ip_src.s_addr));
+	}
+}
+#endif