diff options
-rw-r--r-- | net/bridge/br_netfilter.c | 107 | ||||
-rw-r--r-- | net/ipv4/ip_options.c | 3 |
2 files changed, 80 insertions, 30 deletions
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 137f23259a93..77f7b5fda45a 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c | |||
@@ -209,6 +209,72 @@ static inline void nf_bridge_update_protocol(struct sk_buff *skb) | |||
209 | skb->protocol = htons(ETH_P_PPP_SES); | 209 | skb->protocol = htons(ETH_P_PPP_SES); |
210 | } | 210 | } |
211 | 211 | ||
212 | /* When handing a packet over to the IP layer | ||
213 | * check whether we have a skb that is in the | ||
214 | * expected format | ||
215 | */ | ||
216 | |||
217 | int br_parse_ip_options(struct sk_buff *skb) | ||
218 | { | ||
219 | struct ip_options *opt; | ||
220 | struct iphdr *iph; | ||
221 | struct net_device *dev = skb->dev; | ||
222 | u32 len; | ||
223 | |||
224 | iph = ip_hdr(skb); | ||
225 | opt = &(IPCB(skb)->opt); | ||
226 | |||
227 | /* Basic sanity checks */ | ||
228 | if (iph->ihl < 5 || iph->version != 4) | ||
229 | goto inhdr_error; | ||
230 | |||
231 | if (!pskb_may_pull(skb, iph->ihl*4)) | ||
232 | goto inhdr_error; | ||
233 | |||
234 | iph = ip_hdr(skb); | ||
235 | if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl))) | ||
236 | goto inhdr_error; | ||
237 | |||
238 | len = ntohs(iph->tot_len); | ||
239 | if (skb->len < len) { | ||
240 | IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INTRUNCATEDPKTS); | ||
241 | goto drop; | ||
242 | } else if (len < (iph->ihl*4)) | ||
243 | goto inhdr_error; | ||
244 | |||
245 | if (pskb_trim_rcsum(skb, len)) { | ||
246 | IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS); | ||
247 | goto drop; | ||
248 | } | ||
249 | |||
250 | /* Zero out the CB buffer if no options present */ | ||
251 | if (iph->ihl == 5) { | ||
252 | memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); | ||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | opt->optlen = iph->ihl*4 - sizeof(struct iphdr); | ||
257 | if (ip_options_compile(dev_net(dev), opt, skb)) | ||
258 | goto inhdr_error; | ||
259 | |||
260 | /* Check correct handling of SRR option */ | ||
261 | if (unlikely(opt->srr)) { | ||
262 | struct in_device *in_dev = __in_dev_get_rcu(dev); | ||
263 | if (in_dev && !IN_DEV_SOURCE_ROUTE(in_dev)) | ||
264 | goto drop; | ||
265 | |||
266 | if (ip_options_rcv_srr(skb)) | ||
267 | goto drop; | ||
268 | } | ||
269 | |||
270 | return 0; | ||
271 | |||
272 | inhdr_error: | ||
273 | IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INHDRERRORS); | ||
274 | drop: | ||
275 | return -1; | ||
276 | } | ||
277 | |||
212 | /* Fill in the header for fragmented IP packets handled by | 278 | /* Fill in the header for fragmented IP packets handled by |
213 | * the IPv4 connection tracking code. | 279 | * the IPv4 connection tracking code. |
214 | */ | 280 | */ |
@@ -549,7 +615,6 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb, | |||
549 | { | 615 | { |
550 | struct net_bridge_port *p; | 616 | struct net_bridge_port *p; |
551 | struct net_bridge *br; | 617 | struct net_bridge *br; |
552 | struct iphdr *iph; | ||
553 | __u32 len = nf_bridge_encap_header_len(skb); | 618 | __u32 len = nf_bridge_encap_header_len(skb); |
554 | 619 | ||
555 | if (unlikely(!pskb_may_pull(skb, len))) | 620 | if (unlikely(!pskb_may_pull(skb, len))) |
@@ -578,28 +643,9 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb, | |||
578 | 643 | ||
579 | nf_bridge_pull_encap_header_rcsum(skb); | 644 | nf_bridge_pull_encap_header_rcsum(skb); |
580 | 645 | ||
581 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) | 646 | if (br_parse_ip_options(skb)) |
582 | goto inhdr_error; | 647 | /* Drop invalid packet */ |
583 | 648 | goto out; | |
584 | iph = ip_hdr(skb); | ||
585 | if (iph->ihl < 5 || iph->version != 4) | ||
586 | goto inhdr_error; | ||
587 | |||
588 | if (!pskb_may_pull(skb, 4 * iph->ihl)) | ||
589 | goto inhdr_error; | ||
590 | |||
591 | iph = ip_hdr(skb); | ||
592 | if (ip_fast_csum((__u8 *) iph, iph->ihl) != 0) | ||
593 | goto inhdr_error; | ||
594 | |||
595 | len = ntohs(iph->tot_len); | ||
596 | if (skb->len < len || len < 4 * iph->ihl) | ||
597 | goto inhdr_error; | ||
598 | |||
599 | pskb_trim_rcsum(skb, len); | ||
600 | |||
601 | /* BUG: Should really parse the IP options here. */ | ||
602 | memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); | ||
603 | 649 | ||
604 | nf_bridge_put(skb->nf_bridge); | 650 | nf_bridge_put(skb->nf_bridge); |
605 | if (!nf_bridge_alloc(skb)) | 651 | if (!nf_bridge_alloc(skb)) |
@@ -614,8 +660,6 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff *skb, | |||
614 | 660 | ||
615 | return NF_STOLEN; | 661 | return NF_STOLEN; |
616 | 662 | ||
617 | inhdr_error: | ||
618 | // IP_INC_STATS_BH(IpInHdrErrors); | ||
619 | out: | 663 | out: |
620 | return NF_DROP; | 664 | return NF_DROP; |
621 | } | 665 | } |
@@ -759,14 +803,19 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff *skb, | |||
759 | #if defined(CONFIG_NF_CONNTRACK_IPV4) || defined(CONFIG_NF_CONNTRACK_IPV4_MODULE) | 803 | #if defined(CONFIG_NF_CONNTRACK_IPV4) || defined(CONFIG_NF_CONNTRACK_IPV4_MODULE) |
760 | static int br_nf_dev_queue_xmit(struct sk_buff *skb) | 804 | static int br_nf_dev_queue_xmit(struct sk_buff *skb) |
761 | { | 805 | { |
806 | int ret; | ||
807 | |||
762 | if (skb->nfct != NULL && skb->protocol == htons(ETH_P_IP) && | 808 | if (skb->nfct != NULL && skb->protocol == htons(ETH_P_IP) && |
763 | skb->len + nf_bridge_mtu_reduction(skb) > skb->dev->mtu && | 809 | skb->len + nf_bridge_mtu_reduction(skb) > skb->dev->mtu && |
764 | !skb_is_gso(skb)) { | 810 | !skb_is_gso(skb)) { |
765 | /* BUG: Should really parse the IP options here. */ | 811 | if (br_parse_ip_options(skb)) |
766 | memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); | 812 | /* Drop invalid packet */ |
767 | return ip_fragment(skb, br_dev_queue_push_xmit); | 813 | return NF_DROP; |
814 | ret = ip_fragment(skb, br_dev_queue_push_xmit); | ||
768 | } else | 815 | } else |
769 | return br_dev_queue_push_xmit(skb); | 816 | ret = br_dev_queue_push_xmit(skb); |
817 | |||
818 | return ret; | ||
770 | } | 819 | } |
771 | #else | 820 | #else |
772 | static int br_nf_dev_queue_xmit(struct sk_buff *skb) | 821 | static int br_nf_dev_queue_xmit(struct sk_buff *skb) |
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index ba9836c488ed..1906fa35860c 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c | |||
@@ -466,7 +466,7 @@ error: | |||
466 | } | 466 | } |
467 | return -EINVAL; | 467 | return -EINVAL; |
468 | } | 468 | } |
469 | 469 | EXPORT_SYMBOL(ip_options_compile); | |
470 | 470 | ||
471 | /* | 471 | /* |
472 | * Undo all the changes done by ip_options_compile(). | 472 | * Undo all the changes done by ip_options_compile(). |
@@ -646,3 +646,4 @@ int ip_options_rcv_srr(struct sk_buff *skb) | |||
646 | } | 646 | } |
647 | return 0; | 647 | return 0; |
648 | } | 648 | } |
649 | EXPORT_SYMBOL(ip_options_rcv_srr); | ||