Commit f2e9de25 authored by Yasuyuki Kozakai's avatar Yasuyuki Kozakai Committed by Patrick McHardy

[NETFILTER]: Fix multiple bugs in hbh match

This patch fixes the following bugs in ip6t_hbh.c.
  - The cast of the pointer to the next IPv6 extension header is wrong.
  - hdrlen may underflow.
  - (u16)*optdesc causes to alignment problem.
  - The calculation of the offset to next option is wrong. In the case
    that the type isn't 0, it should be "Opt Data Len" field + 2
    (see RFC2460).
Signed-off-by: default avatarYasuyuki KOZAKAI <yasuyuki.kozakai@toshiba.co.jp>
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
parent 863a5235
...@@ -19,8 +19,6 @@ ...@@ -19,8 +19,6 @@
#include <linux/netfilter_ipv6/ip6_tables.h> #include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_ipv6/ip6t_opts.h> #include <linux/netfilter_ipv6/ip6t_opts.h>
#define LOW(n) (n & 0x00FF)
#define HOPBYHOP 1 #define HOPBYHOP 1
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -47,8 +45,8 @@ MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); ...@@ -47,8 +45,8 @@ MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
* 0 -> invariant * 0 -> invariant
* 1 -> can change the routing * 1 -> can change the routing
* (Type & 0x1F) Type * (Type & 0x1F) Type
* 0 -> PAD0 (only 1 byte!) * 0 -> Pad1 (only 1 byte!)
* 1 -> PAD1 LENGTH info (total length = length + 2) * 1 -> PadN LENGTH info (total length = length + 2)
* C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k ) * C0 | 2 -> JUMBO 4 x x x x ( xxxx > 64k )
* 5 -> RTALERT 2 x x * 5 -> RTALERT 2 x x
*/ */
...@@ -70,7 +68,8 @@ match(const struct sk_buff *skb, ...@@ -70,7 +68,8 @@ match(const struct sk_buff *skb,
unsigned int ptr; unsigned int ptr;
unsigned int hdrlen = 0; unsigned int hdrlen = 0;
unsigned int ret = 0; unsigned int ret = 0;
u_int16_t *optdesc = NULL; u8 *opttype = NULL;
unsigned int optlen;
/* type of the 1st exthdr */ /* type of the 1st exthdr */
nexthdr = skb->nh.ipv6h->nexthdr; nexthdr = skb->nh.ipv6h->nexthdr;
...@@ -97,7 +96,7 @@ match(const struct sk_buff *skb, ...@@ -97,7 +96,7 @@ match(const struct sk_buff *skb,
break; break;
} }
hdr=(void *)(skb->data)+ptr; hdr = (void *)(skb->data + ptr);
/* Calculate the header length */ /* Calculate the header length */
if (nexthdr == NEXTHDR_FRAGMENT) { if (nexthdr == NEXTHDR_FRAGMENT) {
...@@ -159,7 +158,7 @@ match(const struct sk_buff *skb, ...@@ -159,7 +158,7 @@ match(const struct sk_buff *skb,
return 0; return 0;
} }
optsh=(void *)(skb->data)+ptr; optsh = (void *)(skb->data + ptr);
DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen); DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, optsh->hdrlen);
...@@ -175,7 +174,6 @@ match(const struct sk_buff *skb, ...@@ -175,7 +174,6 @@ match(const struct sk_buff *skb,
((optinfo->hdrlen == hdrlen) ^ ((optinfo->hdrlen == hdrlen) ^
!!(optinfo->invflags & IP6T_OPTS_INV_LEN))); !!(optinfo->invflags & IP6T_OPTS_INV_LEN)));
temp = len = 0;
ptr += 2; ptr += 2;
hdrlen -= 2; hdrlen -= 2;
if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){ if ( !(optinfo->flags & IP6T_OPTS_OPTS) ){
...@@ -186,48 +184,52 @@ match(const struct sk_buff *skb, ...@@ -186,48 +184,52 @@ match(const struct sk_buff *skb,
DEBUGP("Strict "); DEBUGP("Strict ");
DEBUGP("#%d ",optinfo->optsnr); DEBUGP("#%d ",optinfo->optsnr);
for(temp=0; temp<optinfo->optsnr; temp++){ for(temp=0; temp<optinfo->optsnr; temp++){
optdesc = (void *)(skb->data)+ptr; /* type field exists ? */
if (ptr > skb->len - 1 || hdrlen < 1)
break;
opttype = (void *)(skb->data + ptr);
/* Type check */ /* Type check */
if ( (unsigned char)*optdesc != if (*opttype != (optinfo->opts[temp] & 0xFF00)>>8){
(optinfo->opts[temp] & 0xFF00)>>8 ){
DEBUGP("Tbad %02X %02X\n", DEBUGP("Tbad %02X %02X\n",
(unsigned char)*optdesc, *opttype,
(optinfo->opts[temp] & (optinfo->opts[temp] & 0xFF00)>>8);
0xFF00)>>8);
return 0; return 0;
} else { } else {
DEBUGP("Tok "); DEBUGP("Tok ");
} }
/* Length check */ /* Length check */
if (((optinfo->opts[temp] & 0x00FF) != 0xFF) && if (*opttype) {
(unsigned char)*optdesc != 0){ u16 spec_len;
if ( ntohs((u16)*optdesc) !=
optinfo->opts[temp] ){ /* length field exists ? */
DEBUGP("Lbad %02X %04X %04X\n", if (ptr > skb->len - 2 || hdrlen < 2)
(unsigned char)*optdesc, break;
ntohs((u16)*optdesc), optlen = *((u8 *)(skb->data + ptr + 1));
optinfo->opts[temp]); spec_len = optinfo->opts[temp] & 0x00FF;
if (spec_len != 0x00FF && spec_len != optlen) {
DEBUGP("Lbad %02X %04X\n", optlen,
spec_len);
return 0; return 0;
} else {
DEBUGP("Lok ");
} }
} DEBUGP("Lok ");
/* Step to the next */ optlen += 2;
if ((unsigned char)*optdesc == 0){
DEBUGP("PAD0 \n");
ptr++;
hdrlen--;
} else { } else {
ptr += LOW(ntohs(*optdesc)); DEBUGP("Pad1\n");
hdrlen -= LOW(ntohs(*optdesc)); optlen = 1;
DEBUGP("len%04X \n",
LOW(ntohs(*optdesc)));
} }
if (ptr > skb->len || ( !hdrlen &&
(temp != optinfo->optsnr - 1))) { /* Step to the next */
DEBUGP("len%04X \n", optlen);
if ((ptr > skb->len - optlen || hdrlen < optlen) &&
(temp < optinfo->optsnr - 1)) {
DEBUGP("new pointer is too large! \n"); DEBUGP("new pointer is too large! \n");
break; break;
} }
ptr += optlen;
hdrlen -= optlen;
} }
if (temp == optinfo->optsnr) if (temp == optinfo->optsnr)
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment