aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Horman <horms@verge.net.au>2013-05-28 16:34:29 -0400
committerDavid S. Miller <davem@davemloft.net>2013-05-29 02:49:07 -0400
commit7cc461900549fc480eb133948649a1edb7eaaa6f (patch)
tree32782f0156c0eb27b2b188d7882e9c2e77d7c8c5
parent158874cac61245b84e939c92c53db7000122b7b0 (diff)
net, ipv4, ipv6: Correct assignment of skb->network_header to skb->tail
This corrects an regression introduced by "net: Use 16bits for *_headers fields of struct skbuff" when NET_SKBUFF_DATA_USES_OFFSET is not set. In that case skb->tail will be a pointer however skb->network_header is now an offset. This patch corrects the problem by adding a wrapper to return skb tail as an offset regardless of the value of NET_SKBUFF_DATA_USES_OFFSET. It seems that skb->tail that this offset may be more than 64k and some care has been taken to treat such cases as an error. Signed-off-by: Simon Horman <horms@verge.net.au> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/skbuff.h9
-rw-r--r--net/core/netpoll.c9
-rw-r--r--net/core/pktgen.c16
-rw-r--r--net/ipv4/ipmr.c8
4 files changed, 38 insertions, 4 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 8f2b830772a8..5f931191cf57 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1391,6 +1391,11 @@ static inline void skb_set_tail_pointer(struct sk_buff *skb, const int offset)
1391 skb_reset_tail_pointer(skb); 1391 skb_reset_tail_pointer(skb);
1392 skb->tail += offset; 1392 skb->tail += offset;
1393} 1393}
1394
1395static inline unsigned long skb_tail_offset(const struct sk_buff *skb)
1396{
1397 return skb->tail;
1398}
1394#else /* NET_SKBUFF_DATA_USES_OFFSET */ 1399#else /* NET_SKBUFF_DATA_USES_OFFSET */
1395static inline unsigned char *skb_tail_pointer(const struct sk_buff *skb) 1400static inline unsigned char *skb_tail_pointer(const struct sk_buff *skb)
1396{ 1401{
@@ -1407,6 +1412,10 @@ static inline void skb_set_tail_pointer(struct sk_buff *skb, const int offset)
1407 skb->tail = skb->data + offset; 1412 skb->tail = skb->data + offset;
1408} 1413}
1409 1414
1415static inline unsigned long skb_tail_offset(const struct sk_buff *skb)
1416{
1417 return skb->tail - skb->head;
1418}
1410#endif /* NET_SKBUFF_DATA_USES_OFFSET */ 1419#endif /* NET_SKBUFF_DATA_USES_OFFSET */
1411 1420
1412/* 1421/*
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 37deedd48bcc..688517c7ff17 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -676,6 +676,8 @@ static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo
676 676
677 spin_lock_irqsave(&npinfo->rx_lock, flags); 677 spin_lock_irqsave(&npinfo->rx_lock, flags);
678 list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) { 678 list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
679 unsigned long tail_offset;
680
679 if (!ipv6_addr_equal(daddr, &np->local_ip.in6)) 681 if (!ipv6_addr_equal(daddr, &np->local_ip.in6))
680 continue; 682 continue;
681 683
@@ -700,7 +702,12 @@ static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo
700 hdr->saddr = *saddr; 702 hdr->saddr = *saddr;
701 hdr->daddr = *daddr; 703 hdr->daddr = *daddr;
702 704
703 send_skb->transport_header = send_skb->tail; 705 tail_offset = skb_tail_offset(skb);
706 if (tail_offset > 0xffff) {
707 kfree_skb(send_skb);
708 continue;
709 }
710 skb_set_network_header(send_skb, tail_offset);
704 skb_put(send_skb, size); 711 skb_put(send_skb, size);
705 712
706 icmp6h = (struct icmp6hdr *)skb_transport_header(skb); 713 icmp6h = (struct icmp6hdr *)skb_transport_header(skb);
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 795498fd4587..d2ede89662be 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -2642,6 +2642,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
2642 __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ 2642 __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */
2643 __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ 2643 __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */
2644 u16 queue_map; 2644 u16 queue_map;
2645 unsigned long tail_offset;
2645 2646
2646 if (pkt_dev->nr_labels) 2647 if (pkt_dev->nr_labels)
2647 protocol = htons(ETH_P_MPLS_UC); 2648 protocol = htons(ETH_P_MPLS_UC);
@@ -2708,7 +2709,12 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
2708 *vlan_encapsulated_proto = htons(ETH_P_IP); 2709 *vlan_encapsulated_proto = htons(ETH_P_IP);
2709 } 2710 }
2710 2711
2711 skb->network_header = skb->tail; 2712 tail_offset = skb_tail_offset(skb);
2713 if (tail_offset > 0xffff) {
2714 kfree_skb(skb);
2715 return NULL;
2716 }
2717 skb_set_network_header(skb, tail_offset);
2712 skb->transport_header = skb->network_header + sizeof(struct iphdr); 2718 skb->transport_header = skb->network_header + sizeof(struct iphdr);
2713 skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr)); 2719 skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr));
2714 skb_set_queue_mapping(skb, queue_map); 2720 skb_set_queue_mapping(skb, queue_map);
@@ -2775,6 +2781,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
2775 __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */ 2781 __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */
2776 __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */ 2782 __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */
2777 u16 queue_map; 2783 u16 queue_map;
2784 unsigned long tail_offset;
2778 2785
2779 if (pkt_dev->nr_labels) 2786 if (pkt_dev->nr_labels)
2780 protocol = htons(ETH_P_MPLS_UC); 2787 protocol = htons(ETH_P_MPLS_UC);
@@ -2822,7 +2829,12 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
2822 *vlan_encapsulated_proto = htons(ETH_P_IPV6); 2829 *vlan_encapsulated_proto = htons(ETH_P_IPV6);
2823 } 2830 }
2824 2831
2825 skb->network_header = skb->tail; 2832 tail_offset = skb_tail_offset(skb);
2833 if (tail_offset > 0xffff) {
2834 kfree_skb(skb);
2835 return NULL;
2836 }
2837 skb_set_network_header(skb, tail_offset);
2826 skb->transport_header = skb->network_header + sizeof(struct ipv6hdr); 2838 skb->transport_header = skb->network_header + sizeof(struct ipv6hdr);
2827 skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr)); 2839 skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr));
2828 skb_set_queue_mapping(skb, queue_map); 2840 skb_set_queue_mapping(skb, queue_map);
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index f975399f3522..df97f0ac1a1c 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -945,6 +945,7 @@ static int ipmr_cache_report(struct mr_table *mrt,
945 struct igmpmsg *msg; 945 struct igmpmsg *msg;
946 struct sock *mroute_sk; 946 struct sock *mroute_sk;
947 int ret; 947 int ret;
948 unsigned long tail_offset;
948 949
949#ifdef CONFIG_IP_PIMSM 950#ifdef CONFIG_IP_PIMSM
950 if (assert == IGMPMSG_WHOLEPKT) 951 if (assert == IGMPMSG_WHOLEPKT)
@@ -980,7 +981,12 @@ static int ipmr_cache_report(struct mr_table *mrt,
980 981
981 /* Copy the IP header */ 982 /* Copy the IP header */
982 983
983 skb->network_header = skb->tail; 984 tail_offset = skb_tail_offset(skb);
985 if (tail_offset > 0xffff) {
986 kfree_skb(skb);
987 return -EINVAL;
988 }
989 skb_set_network_header(skb, tail_offset);
984 skb_put(skb, ihl); 990 skb_put(skb, ihl);
985 skb_copy_to_linear_data(skb, pkt->data, ihl); 991 skb_copy_to_linear_data(skb, pkt->data, ihl);
986 ip_hdr(skb)->protocol = 0; /* Flag to the kernel this is a route add */ 992 ip_hdr(skb)->protocol = 0; /* Flag to the kernel this is a route add */