netlim patch

Paul Rusty Russell (Paul.Russell@rustcorp.com.au)
Sun, 02 Nov 1997 15:39:07 +1100


Hi all,

The following patch (tested against 2.1.59, but patches clean to .61)
differentiates between different callers to net_ratelimit() so that
one message flooding the system won't stop others; each one is counted
individually. Otherwise a clever attacker could mask an attack with
the current code, or a chronic network problem could mask other
problems.

I've also moved it out of net/ipv4 into net/core/, but it could easily
be moved out of net/ entirely and renamed "checklimit()" or something;
there might be other parts of the kernel that want to avoid
flooding...

Also added a convenience macro "netlim_printk".

Rusty.
--- linux/./include/linux/net.h.~1~ Fri Jun 27 05:33:40 1997
+++ linux/./include/linux/net.h Sun Oct 19 16:33:26 1997
@@ -137,7 +137,13 @@
extern int sock_readv_writev(int type, struct inode * inode, struct file * file,
const struct iovec * iov, long count, long size);

-int net_ratelimit(void);
+#define net_ratelimit() net_checklimit(__FILE__,__LINE__)
+
+/* Convenience macro for most common use of net_ratelimit*/
+#define netlim_printk(format, args...) \
+do { if (net_ratelimit()) printk(format , ## args); } while (0)
+
+int net_checklimit(const char filename[], int linenum);

#endif /* __KERNEL__ */
#endif /* _LINUX_NET_H */
--- linux/./net/core/Makefile.~1~ Sun Oct 19 16:00:44 1997
+++ linux/./net/core/Makefile Sun Oct 19 16:01:54 1997
@@ -10,7 +10,7 @@
O_TARGET := core.o

O_OBJS := sock.o skbuff.o iovec.o datagram.o dst.o scm.o \
- neighbour.o
+ neighbour.o limit.o

ifeq ($(CONFIG_SYSCTL),y)
O_OBJS += sysctl_net_core.o
--- linux/./net/core/limit.c.~1~ Sun Oct 19 16:00:44 1997
+++ linux/./net/core/limit.c Mon Oct 20 11:14:54 1997
@@ -0,0 +1,70 @@
+/* This enforces a rate limit: not more than one of these kernel
+ * messages every 5secs to make a denial-of-service attack impossible.
+ *
+ * All printk()s which could be evoked by an external source should use
+ * the macro netlim_printk or check net_ratelimit()
+ *
+ * See linux/net.h for these macros.
+ *
+ * Author: Paul `Rusty' Russell (Paul.Russell@rustcorp.com.au).
+ * Original by: Andi Kleen.
+ */
+#include <linux/kernel.h>
+#include <linux/net.h>
+#include <linux/malloc.h>
+#include <linux/sched.h>
+
+struct limit_chain
+{
+ struct limit_chain *next;
+ const char *filename;
+ int linenum;
+ unsigned long int time;
+ int missed;
+};
+
+static void limit_expire(struct limit_chain **entry)
+{
+ struct limit_chain *del = *entry;
+
+ if (del->missed)
+ printk(KERN_WARNING "ipv4: (%d messages suppressed. Flood?)\n",
+ del->missed);
+ *entry = del->next;
+ kfree(del);
+}
+
+int net_checklimit(const char *filename, int linenum)
+{
+ static struct limit_chain *chain;
+ struct limit_chain *i, *match = NULL;
+
+ /* This always points to the pointer to i (used for deletion). */
+ struct limit_chain **ptr = &chain;
+
+ /* Look for this message, and expire old messages. */
+ for (i = chain; i; ptr=&(i->next), i=i->next) {
+ if (jiffies - i->time >= 5*HZ) limit_expire(ptr);
+ else if (i->linenum == linenum
+ && strcmp(i->filename, filename) == 0)
+ match = i;
+ }
+
+ if (match) {
+ match->missed++;
+ return 0;
+ }
+ else {
+ i = kmalloc(sizeof(struct limit_chain), GFP_KERNEL);
+ /* Drop the message -- hey, we got other problems. */
+ if (!i) return 0;
+
+ i->next = chain;
+ i->filename = filename;
+ i->linenum = linenum;
+ i->time = jiffies;
+ i->missed = 0;
+ chain = i;
+ return 1;
+ }
+}
--- linux/net/ipv4/utils.c.~1~ Fri Jun 27 05:33:41 1997
+++ linux/net/ipv4/utils.c Sun Oct 19 16:00:44 1997
@@ -14,6 +14,7 @@
* Alan Cox : verify_area check.
* Alan Cox : removed old debugging.
* Andi Kleen : add net_ratelimit()
+ * Paul Russell : moved ratelimit to ../core/.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -87,26 +88,4 @@
}
}
return(htonl(l));
-}
-
-/*
- * This enforces a rate limit: not more than one kernel message
- * every 5secs to make a denial-of-service attack impossible.
- *
- * All warning printk()s should be guarded by this function.
- */
-int net_ratelimit(void)
-{
- static unsigned long last_msg;
- static int missed;
-
- if ((jiffies - last_msg) >= 5*HZ) {
- if (missed)
- printk(KERN_WARNING "ipv4: (%d messages suppressed. Flood?)\n", missed);
- missed = 0;
- last_msg = jiffies;
- return 1;
- }
- missed++;
- return 0;
}

--
 .sig lost in the mail.