]> err.no Git - linux-2.6/blobdiff - net/ipv4/netfilter/nf_nat_snmp_basic.c
netfilter: nf_nat_snmp_basic: fix a range check in NAT for SNMP
[linux-2.6] / net / ipv4 / netfilter / nf_nat_snmp_basic.c
index 000e080bac5c49ec35541cee0f8d93ebf4779452..ffeaffc3fffe6c31c78e858b9a1fa61fe71ba03e 100644 (file)
@@ -220,7 +220,7 @@ static unsigned char asn1_length_decode(struct asn1_ctx *ctx,
                if (ch < 0x80)
                        *len = ch;
                else {
-                       cnt = (unsigned char) (ch & 0x7F);
+                       cnt = ch & 0x7F;
                        *len = 0;
 
                        while (cnt > 0) {
@@ -232,6 +232,11 @@ static unsigned char asn1_length_decode(struct asn1_ctx *ctx,
                        }
                }
        }
+
+       /* don't trust len bigger than ctx buffer */
+       if (*len > ctx->end - ctx->pointer)
+               return 0;
+
        return 1;
 }
 
@@ -250,6 +255,10 @@ static unsigned char asn1_header_decode(struct asn1_ctx *ctx,
        if (!asn1_length_decode(ctx, &def, &len))
                return 0;
 
+       /* primitive shall be definite, indefinite shall be constructed */
+       if (*con == ASN1_PRI && !def)
+               return 0;
+
        if (def)
                *eoc = ctx->pointer + len;
        else
@@ -430,10 +439,15 @@ static unsigned char asn1_oid_decode(struct asn1_ctx *ctx,
                                     unsigned int *len)
 {
        unsigned long subid;
-       unsigned int  size;
        unsigned long *optr;
+       size_t size;
 
        size = eoc - ctx->pointer + 1;
+
+       /* first subid actually encodes first two subids */
+       if (size < 2 || size > ULONG_MAX/sizeof(unsigned long))
+               return 0;
+
        *oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC);
        if (*oid == NULL) {
                if (net_ratelimit())
@@ -618,8 +632,7 @@ struct snmp_cnv
        int syntax;
 };
 
-static struct snmp_cnv snmp_conv [] =
-{
+static const struct snmp_cnv snmp_conv[] = {
        {ASN1_UNI, ASN1_NUL, SNMP_NULL},
        {ASN1_UNI, ASN1_INT, SNMP_INTEGER},
        {ASN1_UNI, ASN1_OTS, SNMP_OCTETSTR},
@@ -644,7 +657,7 @@ static unsigned char snmp_tag_cls2syntax(unsigned int tag,
                                         unsigned int cls,
                                         unsigned short *syntax)
 {
-       struct snmp_cnv *cnv;
+       const struct snmp_cnv *cnv;
 
        cnv = snmp_conv;
 
@@ -904,7 +917,7 @@ static inline void mangle_address(unsigned char *begin,
                u_int32_t old;
 
                if (debug)
-                       memcpy(&old, (unsigned char *)addr, sizeof(old));
+                       memcpy(&old, addr, sizeof(old));
 
                *addr = map->to;
 
@@ -999,7 +1012,7 @@ err_id_free:
  *
  *****************************************************************************/
 
-static void hex_dump(unsigned char *buf, size_t len)
+static void hex_dump(const unsigned char *buf, size_t len)
 {
        size_t i;
 
@@ -1080,7 +1093,7 @@ static int snmp_parse_mangle(unsigned char *msg,
        if (cls != ASN1_CTX || con != ASN1_CON)
                return 0;
        if (debug > 1) {
-               unsigned char *pdus[] = {
+               static const unsigned char *const pdus[] = {
                        [SNMP_PDU_GET] = "get",
                        [SNMP_PDU_NEXT] = "get-next",
                        [SNMP_PDU_RESPONSE] = "response",
@@ -1232,8 +1245,8 @@ static int help(struct sk_buff *skb, unsigned int protoff,
 {
        int dir = CTINFO2DIR(ctinfo);
        unsigned int ret;
-       struct iphdr *iph = ip_hdr(skb);
-       struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph + iph->ihl);
+       const struct iphdr *iph = ip_hdr(skb);
+       const struct udphdr *udph = (struct udphdr *)((__be32 *)iph + iph->ihl);
 
        /* SNMP replies and originating SNMP traps get mangled */
        if (udph->source == htons(SNMP_PORT) && dir != IP_CT_DIR_REPLY)