diff options
Diffstat (limited to 'net/sched')
-rw-r--r-- | net/sched/act_nat.c | 23 | ||||
-rw-r--r-- | net/sched/cls_flow.c | 96 | ||||
-rw-r--r-- | net/sched/cls_rsvp.h | 12 | ||||
-rw-r--r-- | net/sched/sch_sfq.c | 36 |
4 files changed, 106 insertions, 61 deletions
diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c index d0386a413e8d..509a2d53a99d 100644 --- a/net/sched/act_nat.c +++ b/net/sched/act_nat.c @@ -114,6 +114,7 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, int egress; int action; int ihl; + int noff; spin_lock(&p->tcf_lock); @@ -132,7 +133,8 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, if (unlikely(action == TC_ACT_SHOT)) goto drop; - if (!pskb_may_pull(skb, sizeof(*iph))) + noff = skb_network_offset(skb); + if (!pskb_may_pull(skb, sizeof(*iph) + noff)) goto drop; iph = ip_hdr(skb); @@ -144,7 +146,7 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, if (!((old_addr ^ addr) & mask)) { if (skb_cloned(skb) && - !skb_clone_writable(skb, sizeof(*iph)) && + !skb_clone_writable(skb, sizeof(*iph) + noff) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) goto drop; @@ -172,9 +174,9 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, { struct tcphdr *tcph; - if (!pskb_may_pull(skb, ihl + sizeof(*tcph)) || + if (!pskb_may_pull(skb, ihl + sizeof(*tcph) + noff) || (skb_cloned(skb) && - !skb_clone_writable(skb, ihl + sizeof(*tcph)) && + !skb_clone_writable(skb, ihl + sizeof(*tcph) + noff) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) goto drop; @@ -186,9 +188,9 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, { struct udphdr *udph; - if (!pskb_may_pull(skb, ihl + sizeof(*udph)) || + if (!pskb_may_pull(skb, ihl + sizeof(*udph) + noff) || (skb_cloned(skb) && - !skb_clone_writable(skb, ihl + sizeof(*udph)) && + !skb_clone_writable(skb, ihl + sizeof(*udph) + noff) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) goto drop; @@ -205,7 +207,7 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, { struct icmphdr *icmph; - if (!pskb_may_pull(skb, ihl + sizeof(*icmph))) + if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + noff)) goto drop; icmph = (void *)(skb_network_header(skb) + ihl); @@ -215,7 +217,8 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, (icmph->type != ICMP_PARAMETERPROB)) break; - if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + sizeof(*iph))) + if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + sizeof(*iph) + + noff)) goto drop; icmph = (void *)(skb_network_header(skb) + ihl); @@ -229,8 +232,8 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a, break; if (skb_cloned(skb) && - !skb_clone_writable(skb, - ihl + sizeof(*icmph) + sizeof(*iph)) && + !skb_clone_writable(skb, ihl + sizeof(*icmph) + + sizeof(*iph) + noff) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) goto drop; diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index f73542d2cdd0..e17096e3913c 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c @@ -65,37 +65,47 @@ static inline u32 addr_fold(void *addr) return (a & 0xFFFFFFFF) ^ (BITS_PER_LONG > 32 ? a >> 32 : 0); } -static u32 flow_get_src(const struct sk_buff *skb) +static u32 flow_get_src(struct sk_buff *skb) { switch (skb->protocol) { case htons(ETH_P_IP): - return ntohl(ip_hdr(skb)->saddr); + if (pskb_network_may_pull(skb, sizeof(struct iphdr))) + return ntohl(ip_hdr(skb)->saddr); + break; case htons(ETH_P_IPV6): - return ntohl(ipv6_hdr(skb)->saddr.s6_addr32[3]); - default: - return addr_fold(skb->sk); + if (pskb_network_may_pull(skb, sizeof(struct ipv6hdr))) + return ntohl(ipv6_hdr(skb)->saddr.s6_addr32[3]); + break; } + + return addr_fold(skb->sk); } -static u32 flow_get_dst(const struct sk_buff *skb) +static u32 flow_get_dst(struct sk_buff *skb) { switch (skb->protocol) { case htons(ETH_P_IP): - return ntohl(ip_hdr(skb)->daddr); + if (pskb_network_may_pull(skb, sizeof(struct iphdr))) + return ntohl(ip_hdr(skb)->daddr); + break; case htons(ETH_P_IPV6): - return ntohl(ipv6_hdr(skb)->daddr.s6_addr32[3]); - default: - return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol; + if (pskb_network_may_pull(skb, sizeof(struct ipv6hdr))) + return ntohl(ipv6_hdr(skb)->daddr.s6_addr32[3]); + break; } + + return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol; } -static u32 flow_get_proto(const struct sk_buff *skb) +static u32 flow_get_proto(struct sk_buff *skb) { switch (skb->protocol) { case htons(ETH_P_IP): - return ip_hdr(skb)->protocol; + return pskb_network_may_pull(skb, sizeof(struct iphdr)) ? + ip_hdr(skb)->protocol : 0; case htons(ETH_P_IPV6): - return ipv6_hdr(skb)->nexthdr; + return pskb_network_may_pull(skb, sizeof(struct ipv6hdr)) ? + ipv6_hdr(skb)->nexthdr : 0; default: return 0; } @@ -116,58 +126,64 @@ static int has_ports(u8 protocol) } } -static u32 flow_get_proto_src(const struct sk_buff *skb) +static u32 flow_get_proto_src(struct sk_buff *skb) { - u32 res = 0; - switch (skb->protocol) { case htons(ETH_P_IP): { - struct iphdr *iph = ip_hdr(skb); + struct iphdr *iph; + if (!pskb_network_may_pull(skb, sizeof(*iph))) + break; + iph = ip_hdr(skb); if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && - has_ports(iph->protocol)) - res = ntohs(*(__be16 *)((void *)iph + iph->ihl * 4)); + has_ports(iph->protocol) && + pskb_network_may_pull(skb, iph->ihl * 4 + 2)) + return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4)); break; } case htons(ETH_P_IPV6): { - struct ipv6hdr *iph = ipv6_hdr(skb); + struct ipv6hdr *iph; + if (!pskb_network_may_pull(skb, sizeof(*iph) + 2)) + break; + iph = ipv6_hdr(skb); if (has_ports(iph->nexthdr)) - res = ntohs(*(__be16 *)&iph[1]); + return ntohs(*(__be16 *)&iph[1]); break; } - default: - res = addr_fold(skb->sk); } - return res; + return addr_fold(skb->sk); } -static u32 flow_get_proto_dst(const struct sk_buff *skb) +static u32 flow_get_proto_dst(struct sk_buff *skb) { - u32 res = 0; - switch (skb->protocol) { case htons(ETH_P_IP): { - struct iphdr *iph = ip_hdr(skb); + struct iphdr *iph; + if (!pskb_network_may_pull(skb, sizeof(*iph))) + break; + iph = ip_hdr(skb); if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && - has_ports(iph->protocol)) - res = ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 + 2)); + has_ports(iph->protocol) && + pskb_network_may_pull(skb, iph->ihl * 4 + 4)) + return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 + 2)); break; } case htons(ETH_P_IPV6): { - struct ipv6hdr *iph = ipv6_hdr(skb); + struct ipv6hdr *iph; + if (!pskb_network_may_pull(skb, sizeof(*iph) + 4)) + break; + iph = ipv6_hdr(skb); if (has_ports(iph->nexthdr)) - res = ntohs(*(__be16 *)((void *)&iph[1] + 2)); + return ntohs(*(__be16 *)((void *)&iph[1] + 2)); break; } - default: - res = addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol; } - return res; + return addr_fold(skb_dst(skb)) ^ (__force u16)skb->protocol; } static u32 flow_get_iif(const struct sk_buff *skb) @@ -211,7 +227,7 @@ static u32 flow_get_nfct(const struct sk_buff *skb) }) #endif -static u32 flow_get_nfct_src(const struct sk_buff *skb) +static u32 flow_get_nfct_src(struct sk_buff *skb) { switch (skb->protocol) { case htons(ETH_P_IP): @@ -223,7 +239,7 @@ fallback: return flow_get_src(skb); } -static u32 flow_get_nfct_dst(const struct sk_buff *skb) +static u32 flow_get_nfct_dst(struct sk_buff *skb) { switch (skb->protocol) { case htons(ETH_P_IP): @@ -235,14 +251,14 @@ fallback: return flow_get_dst(skb); } -static u32 flow_get_nfct_proto_src(const struct sk_buff *skb) +static u32 flow_get_nfct_proto_src(struct sk_buff *skb) { return ntohs(CTTUPLE(skb, src.u.all)); fallback: return flow_get_proto_src(skb); } -static u32 flow_get_nfct_proto_dst(const struct sk_buff *skb) +static u32 flow_get_nfct_proto_dst(struct sk_buff *skb) { return ntohs(CTTUPLE(skb, dst.u.all)); fallback: @@ -281,7 +297,7 @@ static u32 flow_get_vlan_tag(const struct sk_buff *skb) return tag & VLAN_VID_MASK; } -static u32 flow_key_get(const struct sk_buff *skb, int key) +static u32 flow_key_get(struct sk_buff *skb, int key) { switch (key) { case FLOW_KEY_SRC: diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h index dd9414e44200..425a1790b048 100644 --- a/net/sched/cls_rsvp.h +++ b/net/sched/cls_rsvp.h @@ -143,9 +143,17 @@ static int rsvp_classify(struct sk_buff *skb, struct tcf_proto *tp, u8 tunnelid = 0; u8 *xprt; #if RSVP_DST_LEN == 4 - struct ipv6hdr *nhptr = ipv6_hdr(skb); + struct ipv6hdr *nhptr; + + if (!pskb_network_may_pull(skb, sizeof(*nhptr))) + return -1; + nhptr = ipv6_hdr(skb); #else - struct iphdr *nhptr = ip_hdr(skb); + struct iphdr *nhptr; + + if (!pskb_network_may_pull(skb, sizeof(*nhptr))) + return -1; + nhptr = ip_hdr(skb); #endif restart: diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index c65762823f5e..534f33231c17 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -122,7 +122,11 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb) switch (skb->protocol) { case htons(ETH_P_IP): { - const struct iphdr *iph = ip_hdr(skb); + const struct iphdr *iph; + + if (!pskb_network_may_pull(skb, sizeof(*iph))) + goto err; + iph = ip_hdr(skb); h = (__force u32)iph->daddr; h2 = (__force u32)iph->saddr ^ iph->protocol; if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) && @@ -131,25 +135,32 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb) iph->protocol == IPPROTO_UDPLITE || iph->protocol == IPPROTO_SCTP || iph->protocol == IPPROTO_DCCP || - iph->protocol == IPPROTO_ESP)) + iph->protocol == IPPROTO_ESP) && + pskb_network_may_pull(skb, iph->ihl * 4 + 4)) h2 ^= *(((u32*)iph) + iph->ihl); break; } case htons(ETH_P_IPV6): { - struct ipv6hdr *iph = ipv6_hdr(skb); + struct ipv6hdr *iph; + + if (!pskb_network_may_pull(skb, sizeof(*iph))) + goto err; + iph = ipv6_hdr(skb); h = (__force u32)iph->daddr.s6_addr32[3]; h2 = (__force u32)iph->saddr.s6_addr32[3] ^ iph->nexthdr; - if (iph->nexthdr == IPPROTO_TCP || - iph->nexthdr == IPPROTO_UDP || - iph->nexthdr == IPPROTO_UDPLITE || - iph->nexthdr == IPPROTO_SCTP || - iph->nexthdr == IPPROTO_DCCP || - iph->nexthdr == IPPROTO_ESP) + if ((iph->nexthdr == IPPROTO_TCP || + iph->nexthdr == IPPROTO_UDP || + iph->nexthdr == IPPROTO_UDPLITE || + iph->nexthdr == IPPROTO_SCTP || + iph->nexthdr == IPPROTO_DCCP || + iph->nexthdr == IPPROTO_ESP) && + pskb_network_may_pull(skb, sizeof(*iph) + 4)) h2 ^= *(u32*)&iph[1]; break; } default: +err: h = (unsigned long)skb_dst(skb) ^ (__force u32)skb->protocol; h2 = (unsigned long)skb->sk; } @@ -502,6 +513,12 @@ static unsigned long sfq_get(struct Qdisc *sch, u32 classid) return 0; } +static unsigned long sfq_bind(struct Qdisc *sch, unsigned long parent, + u32 classid) +{ + return 0; +} + static struct tcf_proto **sfq_find_tcf(struct Qdisc *sch, unsigned long cl) { struct sfq_sched_data *q = qdisc_priv(sch); @@ -556,6 +573,7 @@ static void sfq_walk(struct Qdisc *sch, struct qdisc_walker *arg) static const struct Qdisc_class_ops sfq_class_ops = { .get = sfq_get, .tcf_chain = sfq_find_tcf, + .bind_tcf = sfq_bind, .dump = sfq_dump_class, .dump_stats = sfq_dump_class_stats, .walk = sfq_walk, |