From 7da803e90827e1ac352b52db8a8ac6e0918a3438 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 24 Nov 2008 17:42:32 +0100 Subject: [PATCH 01/11] doc: add manpages for xt_ECHO and xt_TEE --- extensions/libxt_ECHO.man | 4 ++++ extensions/libxt_TEE.man | 8 ++++++++ 2 files changed, 12 insertions(+) create mode 100644 extensions/libxt_ECHO.man create mode 100644 extensions/libxt_TEE.man diff --git a/extensions/libxt_ECHO.man b/extensions/libxt_ECHO.man new file mode 100644 index 0000000..83babdc --- /dev/null +++ b/extensions/libxt_ECHO.man @@ -0,0 +1,4 @@ +The \fBECHO\fP target will send back all packets it received. It serves as an +examples for an Xtables target. +.PP +ECHO takes no options. diff --git a/extensions/libxt_TEE.man b/extensions/libxt_TEE.man new file mode 100644 index 0000000..3fe6aca --- /dev/null +++ b/extensions/libxt_TEE.man @@ -0,0 +1,8 @@ +The \fBTEE\fP target will clone a packet and redirect this clone to another +machine on the \fBlocal\fP network segment. In other words, the nexthop +must be the target, or you will have to configure the nexthop to forward it +further if so desired. +.TP +\fB--gw\fP \fIipaddr\fP +Send the cloned packet to the host reachable at the given IP address. +Use of 0.0.0.0 (for IPv4 packets) or :: (IPv6) is invalid. From 22db3bcb9ced4ce1b59d4fec45614ef318ffbd80 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 26 Nov 2008 00:36:45 +0100 Subject: [PATCH 02/11] ipp2p: kazaa code cleanup --- extensions/xt_ipp2p.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/extensions/xt_ipp2p.c b/extensions/xt_ipp2p.c index 5ea367c..5f25582 100644 --- a/extensions/xt_ipp2p.c +++ b/extensions/xt_ipp2p.c @@ -600,24 +600,28 @@ search_all_gnu(const unsigned char *payload, const unsigned int plen) static unsigned int search_all_kazaa(const unsigned char *payload, const unsigned int plen) { - if (payload[plen-2] == 0x0d && payload[plen-1] == 0x0a) { - if (memcmp(payload, "GIVE ", 5) == 0) - return IPP2P_KAZAA * 100 + 1; + if (payload[plen-2] != 0x0d || payload[plen-1] != 0x0a) + return 0; - if (memcmp(payload, "GET /", 5) == 0) { - uint16_t c = 8; - const uint16_t end = plen - 22; + if (memcmp(payload, "GIVE ", 5) == 0) + return IPP2P_KAZAA * 100 + 1; - while (c < end) { - if (payload[c] == 0x0a && - payload[c+1] == 0x0d && - (memcmp(&payload[c+2], "X-Kazaa-Username: ", 18) == 0 || - memcmp(&payload[c+2], "User-Agent: PeerEnabler/", 24) == 0)) - return IPP2P_KAZAA * 100 + 2; - c++; - } + if (memcmp(payload, "GET /", 5) == 0) { + uint16_t c = 8; + const uint16_t end = plen - 22; + + for (c = 8; c < end; ++c) { + if (payload[c] != 0x0a) + continue; + if (payload[c+1] != 0x0d) + continue; + if (memcmp(&payload[c+2], "X-Kazaa-Username: ", 18) == 0) + return IPP2P_KAZAA * 100 + 2; + if (memcmp(&payload[c+2], "User-Agent: PeerEnabler/", 24) == 0) + return IPP2P_KAZAA * 100 + 2; } } + return 0; } From ee968691d758dbff145c4d237fc52c10683225f5 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 26 Nov 2008 00:47:36 +0100 Subject: [PATCH 03/11] ipp2p: fix newline inspection in kazaa LFCR looks suspect, it should most likely be CRLF. --- extensions/xt_ipp2p.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/xt_ipp2p.c b/extensions/xt_ipp2p.c index 5f25582..806eb04 100644 --- a/extensions/xt_ipp2p.c +++ b/extensions/xt_ipp2p.c @@ -611,9 +611,9 @@ search_all_kazaa(const unsigned char *payload, const unsigned int plen) const uint16_t end = plen - 22; for (c = 8; c < end; ++c) { - if (payload[c] != 0x0a) + if (payload[c] != 0x0d) continue; - if (payload[c+1] != 0x0d) + if (payload[c+1] != 0x0a) continue; if (memcmp(&payload[c+2], "X-Kazaa-Username: ", 18) == 0) return IPP2P_KAZAA * 100 + 2; From 94ecf3847b8c91b532b2a367a778cccc4b2fa6d2 Mon Sep 17 00:00:00 2001 From: John Haxby Date: Tue, 2 Dec 2008 17:46:36 +0000 Subject: [PATCH 04/11] xt_SYSRQ: improve security I want to be able to use SYSRQ to reboot, crash or partially diagnose machines that become unresponsive for one reason or another. These machines, typically, are blades or rack mounted machines that do not have a PS/2 connection for a keyboard and the old method of wheeling round a "crash trolley" that has a monitor and a keyboard on it no longer works: USB keyboards rarely, if ever, work because by the time the machine is responding only to a ping, udev is incapable of setting up a new keyboard. This patch extends the xt_SYSRQ module to avoid both disclosing the sysrq password and preventing replay. This is done by changing the request packet from the simple "" to a slightly more complex ",,,". The hash is the sha1 checksum of ",,,". A request can be constructed in a small shell script (see manpage). Verification of the hash in xt_SYSRQ follows much the same process. The sequence number, seqno, is initialised to the current time (in seconds) when the xt_SYSRQ module is loaded and is updated each time a valid request is received. A request with a sequence number less than the current sequence number or a wrong hash is silently ignored. (Using the time for the sequence number assumes (requires) that time doesn't go backwards on a reboot and that the requester and victim have reasonably synchronized clocks.) The random salt is there to prevent pre-computed dictionary attacks difficult: dictionary attacks are still feasible if you capture a packet because the hash is computed quickly -- taking perhaps several milliseconds to compute a more complex hash in xt_SYSRQ when the machine is unresponsive is probably not the best thing you could do. However, cracking, say, a random 32 character password would take some time and is probably beyond what the people in the target untrustworthy environment are prepared to do or have the resources for. It almost goes without saying that no two victim machines should use the same password. Finally, the module allocates all the resources it need at module initialisation time on the assumption that if things are going badly resource allocation is going to be troublesome. --- extensions/libxt_SYSRQ.man | 73 ++++++++++----- extensions/xt_SYSRQ.c | 178 +++++++++++++++++++++++++++++++++---- 2 files changed, 215 insertions(+), 36 deletions(-) diff --git a/extensions/libxt_SYSRQ.man b/extensions/libxt_SYSRQ.man index 91c945d..5cd87a3 100644 --- a/extensions/libxt_SYSRQ.man +++ b/extensions/libxt_SYSRQ.man @@ -1,17 +1,19 @@ The SYSRQ target allows to remotely trigger sysrq on the local machine over the network. This can be useful when vital parts of the machine hang, for example an oops in a filesystem causing locks to be not released and processes to get -stuck as a result -- if still possible, use /proc/sysrq-trigger. Even when +stuck as a result - if still possible, use /proc/sysrq-trigger. Even when processes are stuck, interrupts are likely to be still processed, and as such, sysrq can be triggered through incoming network packets. .PP -This xt_SYSRQ implementation does not use any encryption, so you should change -the SYSRQ password after use unless you have made sure it was transmitted -securely and no one sniffed the network, e.g. by use of an IPsec tunnel whose -endpoint is at the machine where you want to trigger the sysrq. Also, you -should limit as to who can issue commands using \fB-s\fP and/or \fB-m mac\fP, -and also that the destination is correct using \fB-d\fP (to protect against -potential broadcast packets), noting that it is still short of MAC/IP spoofing: +The xt_SYSRQ implementation uses a salted hash and a sequence number to prevent +network sniffers from either guessing the password or replaying earlier +requests. The initial sequence number comes from the time of day so you will +have a small window of vulnerability should time go backwards at a reboot. +However, the file /sys/module/xt_SYSREQ/seqno can be used to both query and +update the current sequence number. Also, you should limit as to who can issue +commands using \fB-s\fP and/or \fB-m mac\fP, and also that the destination is +correct using \fB-d\fP (to protect against potential broadcast packets), noting +that it is still short of MAC/IP spoofing: .IP -A INPUT -s 10.10.25.1 -m mac --mac-source aa:bb:cc:dd:ee:ff -d 10.10.25.7 -p udp --dport 9 -j SYSRQ @@ -20,28 +22,59 @@ potential broadcast packets), noting that it is still short of MAC/IP spoofing: ipsec --proto esp --tunnel-src 10.10.25.1 --tunnel-dst 10.10.25.7 -p udp --dport 9 -j SYSRQ .PP +You should also limit the rate at which connections can be received to limit +the CPU time taken by illegal requests, for example: +.IP +-A INPUT 0s 10.10.25.1 -m mac --mac-source aa:bb:cc:dd:ee:ff -d 10.10.25.7 +-p udp --dport 9 -m limit --limit 5/minute -j SYSRQ +.PP This extension does not take any options. The \fB-p udp\fP options are required. .PP The SYSRQ password can be changed through -/sys/module/xt_SYSRQ/parameters/password; note you need to use `echo -n` to -not add a newline to the password, i.e. +/sys/module/xt_SYSRQ/parameters/password, for example: .IP -echo -n "password" >/sys/.../password +echo -n "password" >/sys/module/xt_SYSRQ/parameters/password .PP Alternatively, the password may be specified at modprobe time, but this is insecure as people can possible see it through ps(1). You can use an option -line in /etc/modprobe.d/sysrq if it is properly guarded, that is, only readable -by root. +line in e.g. /etc/modprobe.d/xt_sysrq if it is properly guarded, that is, only +readable by root. .IP options xt_SYSRQ password=cookies .PP -To trigger SYSRQ from a remote host, just use netcat or socat, specifying the -action (only one) as first character, followed by the password: +The hash algorithm can also be specified as a module option, for example, to +use SHA-256 instead of the default SHA-1: .IP -echo -n "scookies" | socat stdin udp-sendto:10.10.25.7:9 -.IP -echo -n "scookies" | netcat -u 10.10.25.7 9 +options xt_SYSRQ hash=sha256 .PP -See the Linux docs for possible sysrq keys. Important ones are: -re(b)oot, power(o)ff, (s)ync filesystems, (u)mount and remount readonly. +The xt_SYSRQ module is normally silent unless a successful request is received, +but the \fIdebug\fP module parameter can be used to find exactly why a +seemingly correct request is not being processed. +.PP +To trigger SYSRQ from a remote host, just use netcat or socat: +.PP +.nf +sysrq_key="s" # the SysRq key(s) +password="password" +seqno="$(date +%s)" +salt="$(dd bs=12 count=1 if=/dev/urandom 2>/dev/null | + openssl enc -base64)" +req="$sysrq_key,$seqno,$salt" +req="$req,$(echo -n "$req,$password" | sha1sum | cut -c1-40)" + +echo "$req" | socat stdin udp-sendto:10.10.25.7:9 +# or +echo "$req" | netcat -uw1 10.10.25.7 9 +.fi +.PP +See the Linux docs for possible sysrq keys. Important ones are: re(b)oot, +power(o)ff, (s)ync filesystems, (u)mount and remount readonly. More than one +sysrq key can be used at once, but bear in mind that, for example, a sync may +not complete before a subsequent reboot or poweroff. +.PP +The hashing scheme should be enough to prevent mis-use of SYSRQ in many +environments, but it is not perfect: take reasonable precautions to +protect your machines. Most importantly ensure that each machine has a +different password; there is scant protection for a SYSRQ packet being +applied to a machine that happens to have the same password. diff --git a/extensions/xt_SYSRQ.c b/extensions/xt_SYSRQ.c index 6036dfe..0da2891 100644 --- a/extensions/xt_SYSRQ.c +++ b/extensions/xt_SYSRQ.c @@ -3,7 +3,6 @@ * Copyright © Jan Engelhardt , 2008 * * Based upon the ipt_SYSRQ idea by Marek Zalem - * xt_SYSRQ does not use hashing or timestamps. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -19,43 +18,140 @@ #include #include #include +#include +#include #include #include "compat_xtables.h" static bool sysrq_once; static char sysrq_password[64]; +static char sysrq_hash[16] = "sha1"; +static long seqno; +static int debug; module_param_string(password, sysrq_password, sizeof(sysrq_password), S_IRUSR | S_IWUSR); +module_param_string(hash, sysrq_hash, sizeof(sysrq_hash), S_IRUSR); +module_param(seqno, long, S_IRUSR | S_IWUSR); +module_param(debug, int, S_IRUSR | S_IWUSR); MODULE_PARM_DESC(password, "password for remote sysrq"); +MODULE_PARM_DESC(hash, "hash algorithm, default sha1"); +MODULE_PARM_DESC(seqno, "sequence number for remote sysrq"); +MODULE_PARM_DESC(debug, "debugging: 0=off, 1=on"); +static struct crypto_hash *tfm; +static int digestsize; +static unsigned char *digest_password; +static unsigned char *digest; +static char *hexdigest; + +/* + * The data is of the form ",,," where + * is a series of sysrq requests; is a sequence number that must be + * greater than the last sequence number; is some random bytes; and + * is the hash of everything up to and including the preceding "," + * together with the password. + * + * For example + * + * salt=$RANDOM + * req="s,$(date +%s),$salt" + * echo "$req,$(echo -n $req,secret | sha1sum | cut -c1-40)" + * + * You will want a better salt and password than that though :-) + */ static unsigned int sysrq_tg(const void *pdata, uint16_t len) { const char *data = pdata; - char c; + int i, n; + struct scatterlist sg[2]; + struct hash_desc desc; + int ret; + long new_seqno = 0; if (*sysrq_password == '\0') { if (!sysrq_once) - printk(KERN_INFO KBUILD_MODNAME "No password set\n"); + printk(KERN_INFO KBUILD_MODNAME ": No password set\n"); sysrq_once = true; return NF_DROP; } - if (len == 0) return NF_DROP; - c = *data; - if (strncmp(&data[1], sysrq_password, len - 1) != 0) { - printk(KERN_INFO KBUILD_MODNAME "Failed attempt - " - "password mismatch\n"); + for (i = 0; sysrq_password[i] != '\0' && + sysrq_password[i] != '\n'; ++i) + /* loop */; + sysrq_password[i] = '\0'; + + i = 0; + for (n = 0; n < len - 1; ++n) { + if (i == 1 && '0' <= data[n] && data[n] <= '9') + new_seqno = 10L * new_seqno + data[n] - '0'; + if (data[n] == ',' && ++i == 3) + break; + } + ++n; + if (i != 3) { + if (debug) + printk(KERN_WARNING KBUILD_MODNAME + ": badly formatted request\n"); + return NF_DROP; + } + if (seqno >= new_seqno) { + if (debug) + printk(KERN_WARNING KBUILD_MODNAME + ": old sequence number ignored\n"); return NF_DROP; } + desc.tfm = tfm; + desc.flags = 0; + ret = crypto_hash_init(&desc); + if (ret != 0) + goto hash_fail; + sg_init_table(sg, 2); + sg_set_buf(&sg[0], data, n); + strcpy(digest_password, sysrq_password); + i = strlen(digest_password); + sg_set_buf(&sg[1], digest_password, i); + ret = crypto_hash_digest(&desc, sg, n + i, digest); + if (ret != 0) + goto hash_fail; + + for (i = 0; i < digestsize; ++i) { + hexdigest[2*i] = + "0123456789abcdef"[(digest[i] >> 4) & 0xf]; + hexdigest[2*i+1] = + "0123456789abcdef"[digest[i] & 0xf]; + } + hexdigest[2*digestsize] = '\0'; + if (len - n < digestsize) { + if (debug) + printk(KERN_INFO KBUILD_MODNAME ": Short digest," + " expected %s\n", hexdigest); + return NF_DROP; + } + if (strncmp(data + n, hexdigest, digestsize) != 0) { + if (debug) + printk(KERN_INFO KBUILD_MODNAME ": Bad digest," + " expected %s\n", hexdigest); + return NF_DROP; + } + + /* Now we trust the requester */ + seqno = new_seqno; + for (i = 0; i < len && data[i] != ','; ++i) { + printk(KERN_INFO KBUILD_MODNAME ": SysRq %c\n", data[i]); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) - handle_sysrq(c, NULL); + handle_sysrq(data[i], NULL); #else - handle_sysrq(c, NULL, NULL); + handle_sysrq(data[i], NULL, NULL); #endif + } return NF_ACCEPT; + + hash_fail: + printk(KERN_WARNING KBUILD_MODNAME ": digest failure\n"); + return NF_DROP; } static unsigned int @@ -73,9 +169,11 @@ sysrq_tg4(struct sk_buff **pskb, const struct xt_target_param *par) udph = (void *)iph + ip_hdrlen(skb); len = ntohs(udph->len) - sizeof(struct udphdr); - printk(KERN_INFO KBUILD_MODNAME ": " NIPQUAD_FMT ":%u -> :%u len=%u\n", - NIPQUAD(iph->saddr), htons(udph->source), htons(udph->dest), - len); + if (debug) + printk(KERN_INFO KBUILD_MODNAME + ": " NIPQUAD_FMT ":%u -> :%u len=%u\n", + NIPQUAD(iph->saddr), htons(udph->source), + htons(udph->dest), len); return sysrq_tg((void *)udph + sizeof(struct udphdr), len); } @@ -94,9 +192,11 @@ sysrq_tg6(struct sk_buff **pskb, const struct xt_target_param *par) udph = udp_hdr(skb); len = ntohs(udph->len) - sizeof(struct udphdr); - printk(KERN_INFO KBUILD_MODNAME ": " NIP6_FMT ":%hu -> :%hu len=%u\n", - NIP6(iph->saddr), ntohs(udph->source), - ntohs(udph->dest), len); + if (debug) + printk(KERN_INFO KBUILD_MODNAME + ": " NIP6_FMT ":%hu -> :%hu len=%u\n", + NIP6(iph->saddr), ntohs(udph->source), + ntohs(udph->dest), len); return sysrq_tg(udph + sizeof(struct udphdr), len); } @@ -146,11 +246,57 @@ static struct xt_target sysrq_tg_reg[] __read_mostly = { static int __init sysrq_tg_init(void) { + struct timeval now; + + tfm = crypto_alloc_hash(sysrq_hash, 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm)) { + printk(KERN_WARNING KBUILD_MODNAME + ": Error: Could not find or load %s hash\n", + sysrq_hash); + tfm = NULL; + goto fail; + } + digestsize = crypto_hash_digestsize(tfm); + digest = kmalloc(digestsize, GFP_KERNEL); + if (digest == NULL) { + printk(KERN_WARNING KBUILD_MODNAME + ": Cannot allocate digest\n"); + goto fail; + } + hexdigest = kmalloc(2 * digestsize + 1, GFP_KERNEL); + if (hexdigest == NULL) { + printk(KERN_WARNING KBUILD_MODNAME + ": Cannot allocate hexdigest\n"); + goto fail; + } + digest_password = kmalloc(sizeof(sysrq_password), GFP_KERNEL); + if (!digest_password) { + printk(KERN_WARNING KBUILD_MODNAME + ": Cannot allocate password digest space\n"); + goto fail; + } + do_gettimeofday(&now); + seqno = now.tv_sec; return xt_register_targets(sysrq_tg_reg, ARRAY_SIZE(sysrq_tg_reg)); + + fail: + if (tfm) + crypto_free_hash(tfm); + if (digest) + kfree(digest); + if (hexdigest) + kfree(hexdigest); + if (digest_password) + kfree(digest_password); + return -EINVAL; } static void __exit sysrq_tg_exit(void) { + crypto_free_hash(tfm); + kfree(digest); + kfree(hexdigest); + kfree(digest_password); return xt_unregister_targets(sysrq_tg_reg, ARRAY_SIZE(sysrq_tg_reg)); } From 6b37f201d7c10a0a7cb45bab5f74aa9b86412dbf Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 10 Dec 2008 15:45:43 +0100 Subject: [PATCH 05/11] xt_SYSRQ: make new code compile for kernel <= 2.6.23 --- extensions/xt_SYSRQ.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/extensions/xt_SYSRQ.c b/extensions/xt_SYSRQ.c index 0da2891..9578ea2 100644 --- a/extensions/xt_SYSRQ.c +++ b/extensions/xt_SYSRQ.c @@ -38,6 +38,7 @@ MODULE_PARM_DESC(hash, "hash algorithm, default sha1"); MODULE_PARM_DESC(seqno, "sequence number for remote sysrq"); MODULE_PARM_DESC(debug, "debugging: 0=off, 1=on"); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) static struct crypto_hash *tfm; static int digestsize; static unsigned char *digest_password; @@ -108,7 +109,9 @@ static unsigned int sysrq_tg(const void *pdata, uint16_t len) ret = crypto_hash_init(&desc); if (ret != 0) goto hash_fail; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) sg_init_table(sg, 2); +#endif sg_set_buf(&sg[0], data, n); strcpy(digest_password, sysrq_password); i = strlen(digest_password); @@ -153,6 +156,37 @@ static unsigned int sysrq_tg(const void *pdata, uint16_t len) printk(KERN_WARNING KBUILD_MODNAME ": digest failure\n"); return NF_DROP; } +#else +static unsigned int sysrq_tg(const void *pdata, uint16_t len) +{ + const char *data = pdata; + char c; + + if (*sysrq_password == '\0') { + if (!sysrq_once) + printk(KERN_INFO KBUILD_MODNAME "No password set\n"); + sysrq_once = true; + return NF_DROP; + } + + if (len == 0) + return NF_DROP; + + c = *data; + if (strncmp(&data[1], sysrq_password, len - 1) != 0) { + printk(KERN_INFO KBUILD_MODNAME "Failed attempt - " + "password mismatch\n"); + return NF_DROP; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) + handle_sysrq(c, NULL); +#else + handle_sysrq(c, NULL, NULL); +#endif + return NF_ACCEPT; +} +#endif static unsigned int sysrq_tg4(struct sk_buff **pskb, const struct xt_target_param *par) @@ -202,6 +236,7 @@ sysrq_tg6(struct sk_buff **pskb, const struct xt_target_param *par) static bool sysrq_tg_check(const struct xt_tgchk_param *par) { + if (par->target->family == NFPROTO_IPV4) { const struct ipt_entry *entry = par->entryinfo; @@ -246,6 +281,7 @@ static struct xt_target sysrq_tg_reg[] __read_mostly = { static int __init sysrq_tg_init(void) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) struct timeval now; tfm = crypto_alloc_hash(sysrq_hash, 0, CRYPTO_ALG_ASYNC); @@ -289,14 +325,20 @@ static int __init sysrq_tg_init(void) if (digest_password) kfree(digest_password); return -EINVAL; +#else + printk(KERN_WARNING "xt_SYSRQ does not provide crypto for <= 2.6.18\n"); + return xt_register_targets(sysrq_tg_reg, ARRAY_SIZE(sysrq_tg_reg)); +#endif } static void __exit sysrq_tg_exit(void) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) crypto_free_hash(tfm); kfree(digest); kfree(hexdigest); kfree(digest_password); +#endif return xt_unregister_targets(sysrq_tg_reg, ARRAY_SIZE(sysrq_tg_reg)); } From 22e73ea31fc53ed8001077593bebbbd486d6f888 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 10 Dec 2008 16:02:21 +0100 Subject: [PATCH 06/11] xt_SYSRQ: src: prefix variables --- extensions/xt_SYSRQ.c | 110 +++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/extensions/xt_SYSRQ.c b/extensions/xt_SYSRQ.c index 9578ea2..4297db5 100644 --- a/extensions/xt_SYSRQ.c +++ b/extensions/xt_SYSRQ.c @@ -26,24 +26,24 @@ static bool sysrq_once; static char sysrq_password[64]; static char sysrq_hash[16] = "sha1"; -static long seqno; -static int debug; +static long sysrq_seqno; +static int sysrq_debug; module_param_string(password, sysrq_password, sizeof(sysrq_password), S_IRUSR | S_IWUSR); module_param_string(hash, sysrq_hash, sizeof(sysrq_hash), S_IRUSR); -module_param(seqno, long, S_IRUSR | S_IWUSR); -module_param(debug, int, S_IRUSR | S_IWUSR); +module_param_named(seqno, sysrq_seqno, long, S_IRUSR | S_IWUSR); +module_param_named(debug, sysrq_debug, int, S_IRUSR | S_IWUSR); MODULE_PARM_DESC(password, "password for remote sysrq"); MODULE_PARM_DESC(hash, "hash algorithm, default sha1"); MODULE_PARM_DESC(seqno, "sequence number for remote sysrq"); MODULE_PARM_DESC(debug, "debugging: 0=off, 1=on"); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) -static struct crypto_hash *tfm; -static int digestsize; -static unsigned char *digest_password; -static unsigned char *digest; -static char *hexdigest; +static struct crypto_hash *sysrq_tfm; +static int sysrq_digest_size; +static unsigned char *sysrq_digest_password; +static unsigned char *sysrq_digest; +static char *sysrq_hexdigest; /* * The data is of the form ",,," where @@ -92,19 +92,19 @@ static unsigned int sysrq_tg(const void *pdata, uint16_t len) } ++n; if (i != 3) { - if (debug) + if (sysrq_debug) printk(KERN_WARNING KBUILD_MODNAME ": badly formatted request\n"); return NF_DROP; } - if (seqno >= new_seqno) { - if (debug) + if (sysrq_seqno >= new_seqno) { + if (sysrq_debug) printk(KERN_WARNING KBUILD_MODNAME ": old sequence number ignored\n"); return NF_DROP; } - desc.tfm = tfm; + desc.tfm = sysrq_tfm; desc.flags = 0; ret = crypto_hash_init(&desc); if (ret != 0) @@ -113,35 +113,35 @@ static unsigned int sysrq_tg(const void *pdata, uint16_t len) sg_init_table(sg, 2); #endif sg_set_buf(&sg[0], data, n); - strcpy(digest_password, sysrq_password); - i = strlen(digest_password); - sg_set_buf(&sg[1], digest_password, i); - ret = crypto_hash_digest(&desc, sg, n + i, digest); + strcpy(sysrq_digest_password, sysrq_password); + i = strlen(sysrq_digest_password); + sg_set_buf(&sg[1], sysrq_digest_password, i); + ret = crypto_hash_digest(&desc, sg, n + i, sysrq_digest); if (ret != 0) goto hash_fail; - for (i = 0; i < digestsize; ++i) { - hexdigest[2*i] = - "0123456789abcdef"[(digest[i] >> 4) & 0xf]; - hexdigest[2*i+1] = - "0123456789abcdef"[digest[i] & 0xf]; + for (i = 0; i < sysrq_digest_size; ++i) { + sysrq_hexdigest[2*i] = + "0123456789abcdef"[(sysrq_digest[i] >> 4) & 0xf]; + sysrq_hexdigest[2*i+1] = + "0123456789abcdef"[sysrq_digest[i] & 0xf]; } - hexdigest[2*digestsize] = '\0'; - if (len - n < digestsize) { - if (debug) + sysrq_hexdigest[2*sysrq_digest_size] = '\0'; + if (len - n < sysrq_digest_size) { + if (sysrq_debug) printk(KERN_INFO KBUILD_MODNAME ": Short digest," - " expected %s\n", hexdigest); + " expected %s\n", sysrq_hexdigest); return NF_DROP; } - if (strncmp(data + n, hexdigest, digestsize) != 0) { - if (debug) + if (strncmp(data + n, sysrq_hexdigest, sysrq_digest_size) != 0) { + if (sysrq_debug) printk(KERN_INFO KBUILD_MODNAME ": Bad digest," - " expected %s\n", hexdigest); + " expected %s\n", sysrq_hexdigest); return NF_DROP; } /* Now we trust the requester */ - seqno = new_seqno; + sysrq_seqno = new_seqno; for (i = 0; i < len && data[i] != ','; ++i) { printk(KERN_INFO KBUILD_MODNAME ": SysRq %c\n", data[i]); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) @@ -203,7 +203,7 @@ sysrq_tg4(struct sk_buff **pskb, const struct xt_target_param *par) udph = (void *)iph + ip_hdrlen(skb); len = ntohs(udph->len) - sizeof(struct udphdr); - if (debug) + if (sysrq_debug) printk(KERN_INFO KBUILD_MODNAME ": " NIPQUAD_FMT ":%u -> :%u len=%u\n", NIPQUAD(iph->saddr), htons(udph->source), @@ -226,7 +226,7 @@ sysrq_tg6(struct sk_buff **pskb, const struct xt_target_param *par) udph = udp_hdr(skb); len = ntohs(udph->len) - sizeof(struct udphdr); - if (debug) + if (sysrq_debug) printk(KERN_INFO KBUILD_MODNAME ": " NIP6_FMT ":%hu -> :%hu len=%u\n", NIP6(iph->saddr), ntohs(udph->source), @@ -284,46 +284,46 @@ static int __init sysrq_tg_init(void) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) struct timeval now; - tfm = crypto_alloc_hash(sysrq_hash, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(tfm)) { + sysrq_tfm = crypto_alloc_hash(sysrq_hash, 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(sysrq_tfm)) { printk(KERN_WARNING KBUILD_MODNAME ": Error: Could not find or load %s hash\n", sysrq_hash); - tfm = NULL; + sysrq_tfm = NULL; goto fail; } - digestsize = crypto_hash_digestsize(tfm); - digest = kmalloc(digestsize, GFP_KERNEL); - if (digest == NULL) { + sysrq_digest_size = crypto_hash_digestsize(sysrq_tfm); + sysrq_digest = kmalloc(sysrq_digest_size, GFP_KERNEL); + if (sysrq_digest == NULL) { printk(KERN_WARNING KBUILD_MODNAME ": Cannot allocate digest\n"); goto fail; } - hexdigest = kmalloc(2 * digestsize + 1, GFP_KERNEL); - if (hexdigest == NULL) { + sysrq_hexdigest = kmalloc(2 * sysrq_digest_size + 1, GFP_KERNEL); + if (sysrq_hexdigest == NULL) { printk(KERN_WARNING KBUILD_MODNAME ": Cannot allocate hexdigest\n"); goto fail; } - digest_password = kmalloc(sizeof(sysrq_password), GFP_KERNEL); - if (!digest_password) { + sysrq_digest_password = kmalloc(sizeof(sysrq_password), GFP_KERNEL); + if (sysrq_digest_password == NULL) { printk(KERN_WARNING KBUILD_MODNAME ": Cannot allocate password digest space\n"); goto fail; } do_gettimeofday(&now); - seqno = now.tv_sec; + sysrq_seqno = now.tv_sec; return xt_register_targets(sysrq_tg_reg, ARRAY_SIZE(sysrq_tg_reg)); fail: - if (tfm) - crypto_free_hash(tfm); - if (digest) - kfree(digest); - if (hexdigest) - kfree(hexdigest); - if (digest_password) - kfree(digest_password); + if (sysrq_tfm) + crypto_free_hash(sysrq_tfm); + if (sysrq_digest) + kfree(sysrq_digest); + if (sysrq_hexdigest) + kfree(sysrq_hexdigest); + if (sysrq_digest_password) + kfree(sysrq_digest_password); return -EINVAL; #else printk(KERN_WARNING "xt_SYSRQ does not provide crypto for <= 2.6.18\n"); @@ -334,10 +334,10 @@ static int __init sysrq_tg_init(void) static void __exit sysrq_tg_exit(void) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) - crypto_free_hash(tfm); - kfree(digest); - kfree(hexdigest); - kfree(digest_password); + crypto_free_hash(sysrq_tfm); + kfree(sysrq_digest); + kfree(sysrq_hexdigest); + kfree(sysrq_digest_password); #endif return xt_unregister_targets(sysrq_tg_reg, ARRAY_SIZE(sysrq_tg_reg)); } From d01a5f3d17212f67357572609c9b473749af8f62 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Wed, 10 Dec 2008 16:28:23 +0100 Subject: [PATCH 07/11] ipp2p: ensure better array bounds checking --- extensions/xt_ipp2p.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/extensions/xt_ipp2p.c b/extensions/xt_ipp2p.c index 806eb04..9c407ea 100644 --- a/extensions/xt_ipp2p.c +++ b/extensions/xt_ipp2p.c @@ -597,29 +597,40 @@ search_all_gnu(const unsigned char *payload, const unsigned int plen) } /* check for KaZaA download commands and other typical data */ +/* plen is guaranteed to be >= 5 (see @matchlist) */ static unsigned int search_all_kazaa(const unsigned char *payload, const unsigned int plen) { + uint16_t c, end, rem; + + if (plen >= 5) { + printk(KERN_WARNING KBUILD_MODNAME ": %s: plen (%u) < 5\n", + __func__, plen); + return 0; + } + if (payload[plen-2] != 0x0d || payload[plen-1] != 0x0a) return 0; if (memcmp(payload, "GIVE ", 5) == 0) return IPP2P_KAZAA * 100 + 1; - if (memcmp(payload, "GET /", 5) == 0) { - uint16_t c = 8; - const uint16_t end = plen - 22; + if (memcmp(payload, "GET /", 5) != 0) + return 0; - for (c = 8; c < end; ++c) { - if (payload[c] != 0x0d) - continue; - if (payload[c+1] != 0x0a) - continue; - if (memcmp(&payload[c+2], "X-Kazaa-Username: ", 18) == 0) - return IPP2P_KAZAA * 100 + 2; - if (memcmp(&payload[c+2], "User-Agent: PeerEnabler/", 24) == 0) - return IPP2P_KAZAA * 100 + 2; - } + end = plen - 18; + rem = plen - 5; + for (c = 5; c < end; ++c, --rem) { + if (payload[c] != 0x0d) + continue; + if (payload[c+1] != 0x0a) + continue; + if (rem >= 18 && + memcmp(&payload[c+2], "X-Kazaa-Username: ", 18) == 0) + return IPP2P_KAZAA * 100 + 2; + if (rem >= 24 && + memcmp(&payload[c+2], "User-Agent: PeerEnabler/", 24) == 0) + return IPP2P_KAZAA * 100 + 2; } return 0; From 598c7ede37a57343b657ea2722ab10c411fe538e Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Thu, 25 Dec 2008 19:57:12 +0100 Subject: [PATCH 08/11] Xtables-addons 1.7 --- Makefile.am | 1 + configure.ac | 8 +++++--- m4/.gitignore | 2 ++ xtables-addons.8.in | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 m4/.gitignore diff --git a/Makefile.am b/Makefile.am index 9493d19..00a10f9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,6 @@ # -*- Makefile -*- +ACLOCAL_AMFLAGS = -I m4 AUTOMAKE_OPTIONS = foreign subdir-objects SUBDIRS = extensions diff --git a/configure.ac b/configure.ac index 3e980aa..8a67ed0 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,9 @@ -AC_INIT([xtables-addons], [1.6]) +AC_INIT([xtables-addons], [1.7]) AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) AC_PROG_INSTALL -AM_INIT_AUTOMAKE +AM_INIT_AUTOMAKE([-Wall]) AC_PROG_CC AM_PROG_CC_C_O AC_DISABLE_STATIC @@ -63,4 +64,5 @@ AC_SUBST([kinclude_CFLAGS]) AC_SUBST([kbuilddir]) AC_SUBST([ksourcedir]) AC_SUBST([xtlibdir]) -AC_OUTPUT([Makefile extensions/GNUmakefile extensions/ipset/GNUmakefile]) +AC_CONFIG_FILES([Makefile extensions/GNUmakefile extensions/ipset/GNUmakefile]) +AC_OUTPUT diff --git a/m4/.gitignore b/m4/.gitignore new file mode 100644 index 0000000..64d9bbc --- /dev/null +++ b/m4/.gitignore @@ -0,0 +1,2 @@ +/libtool.m4 +/lt*.m4 diff --git a/xtables-addons.8.in b/xtables-addons.8.in index a0ce83c..b62c6b3 100644 --- a/xtables-addons.8.in +++ b/xtables-addons.8.in @@ -1,4 +1,4 @@ -.TH xtables\-addons 8 2008\-11\-18 +.TH xtables\-addons 8 "v1.7 (2008\-12\-25)" "" "v1.7 (2008\-12\-25)" .SH NAME Xtables\-addons - additional extensions for iptables, ip6tables, etc. .SH TARGETS From 31c01cf1073d8416dbfc946631ad75e383137160 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sat, 10 Jan 2009 05:23:43 +0100 Subject: [PATCH 09/11] portscan: update manpage about --grscan caveats --- extensions/libxt_portscan.man | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/extensions/libxt_portscan.man b/extensions/libxt_portscan.man index 60a4c1a..aaa162f 100644 --- a/extensions/libxt_portscan.man +++ b/extensions/libxt_portscan.man @@ -20,7 +20,11 @@ connection was torn down after completion of the 3-way handshake. \fB--grscan\fR Match if data in the connection only flew in the direction of the remote side, e.g. if the connection was terminated after a locally running daemon sent its -identification. (e.g. openssh) +identification. (E.g. openssh, smtp, ftpd.) This may falsely trigger on +warranted single-direction data flows, usually bulk data transfers such as +FTP DATA connections or IRC DCC. Grab Scan Detection should only be used on +ports where a protocol runs that is guaranteed to do a bidirectional exchange +of bytes. .PP NOTE: Some clients (Windows XP for example) may do what looks like a SYN scan, so be advised to carefully use xt_portscan in conjunction with blocking rules, From 1fd1787a1c824ddb968d29ac97f280f17c028c33 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sat, 10 Jan 2009 09:57:44 +0100 Subject: [PATCH 10/11] TEE: limit iptables module to NFPROTO_IPV4 The code here is only usable with IPv4. --- extensions/libxt_TEE.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extensions/libxt_TEE.c b/extensions/libxt_TEE.c index 18638b8..f2d788e 100644 --- a/extensions/libxt_TEE.c +++ b/extensions/libxt_TEE.c @@ -98,6 +98,8 @@ static void tee_tg_save(const void *ip, const struct xt_entry_target *target) static struct xtables_target tee_tg_reg = { .name = "TEE", .version = XTABLES_VERSION, + .revision = 0, + .family = PF_INET, .size = XT_ALIGN(sizeof(struct xt_tee_tginfo)), .userspacesize = XT_ALIGN(sizeof(struct xt_tee_tginfo)), .help = tee_tg_help, From d523158e924f01bec1550a0f848a2edf353b1353 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sat, 10 Jan 2009 10:01:27 +0100 Subject: [PATCH 11/11] TEE: iptables -nL and -L produced conversely output --- extensions/libxt_TEE.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/libxt_TEE.c b/extensions/libxt_TEE.c index f2d788e..f6d5583 100644 --- a/extensions/libxt_TEE.c +++ b/extensions/libxt_TEE.c @@ -83,9 +83,9 @@ static void tee_tg_print(const void *ip, const struct xt_entry_target *target, const struct xt_tee_tginfo *info = (const void *)target->data; if (numeric) - printf("TEE gw:%s ", ipaddr_to_anyname(&info->gw.in)); - else printf("TEE gw:%s ", ipaddr_to_numeric(&info->gw.in)); + else + printf("TEE gw:%s ", ipaddr_to_anyname(&info->gw.in)); } static void tee_tg_save(const void *ip, const struct xt_entry_target *target)