batman-adv: 2013.3.0 updated stability fixes
authorMarek Lindner <lindner_marek@yahoo.de>
Thu, 15 Aug 2013 09:36:37 +0000 (17:36 +0800)
committerMarek Lindner <lindner_marek@yahoo.de>
Thu, 15 Aug 2013 09:36:37 +0000 (17:36 +0800)
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
batman-adv/Makefile
batman-adv/patches/0001-batman-adv-fix-potential-kernel-paging-errors-for-un.patch [new file with mode: 0644]

index 6db66a6913ef74504bd9f84643bd1e37fdd9c590..f8dfeadf028777d0f93d00cf19927c86a78b0bb5 100644 (file)
@@ -12,7 +12,7 @@ PKG_NAME:=batman-adv
 
 PKG_VERSION:=2013.3.0
 BATCTL_VERSION:=2013.3.0
-PKG_RELEASE:=4
+PKG_RELEASE:=5
 PKG_MD5SUM:=d070c0879cd8fe8125315a4566fabd2d
 BATCTL_MD5SUM:=747535b0296f0013a6f99373a51d41fc
 
diff --git a/batman-adv/patches/0001-batman-adv-fix-potential-kernel-paging-errors-for-un.patch b/batman-adv/patches/0001-batman-adv-fix-potential-kernel-paging-errors-for-un.patch
new file mode 100644 (file)
index 0000000..d16dce4
--- /dev/null
@@ -0,0 +1,203 @@
+From c98c3e521913b8dd5fee4d3b90dc9ed7a47e5bee Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Linus=20L=C3=BCssing?= <linus.luessing@web.de>
+Date: Tue, 6 Aug 2013 20:21:15 +0200
+Subject: [PATCH] batman-adv: fix potential kernel paging errors for unicast
+ transmissions
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+There are several functions which might reallocate skb data. Currently
+some places keep reusing their old ethhdr pointer regardless of whether
+they became invalid after such a reallocation or not. This potentially
+leads to kernel paging errors.
+
+This patch fixes these by refetching the ethdr pointer after the
+potential reallocations.
+
+Signed-off-by: Linus Lüssing <linus.luessing@web.de>
+Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
+---
+ bridge_loop_avoidance.c |    2 ++
+ gateway_client.c        |   13 ++++++++++++-
+ gateway_client.h        |    3 +--
+ soft-interface.c        |    9 ++++++++-
+ unicast.c               |   13 ++++++++++---
+ 5 files changed, 33 insertions(+), 7 deletions(-)
+
+diff --git a/bridge_loop_avoidance.c b/bridge_loop_avoidance.c
+index e14531f..264de88 100644
+--- a/bridge_loop_avoidance.c
++++ b/bridge_loop_avoidance.c
+@@ -1529,6 +1529,8 @@ out:
+  * in these cases, the skb is further handled by this function and
+  * returns 1, otherwise it returns 0 and the caller shall further
+  * process the skb.
++ *
++ * This call might reallocate skb data.
+  */
+ int batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb,
+                 unsigned short vid)
+diff --git a/gateway_client.c b/gateway_client.c
+index f105219..7614af3 100644
+--- a/gateway_client.c
++++ b/gateway_client.c
+@@ -508,6 +508,7 @@ out:
+       return 0;
+ }
++/* this call might reallocate skb data */
+ static bool batadv_is_type_dhcprequest(struct sk_buff *skb, int header_len)
+ {
+       int ret = false;
+@@ -568,6 +569,7 @@ out:
+       return ret;
+ }
++/* this call might reallocate skb data */
+ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
+ {
+       struct ethhdr *ethhdr;
+@@ -619,6 +621,12 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
+       if (!pskb_may_pull(skb, *header_len + sizeof(*udphdr)))
+               return false;
++
++      /* skb->data might have been reallocated by pskb_may_pull() */
++      ethhdr = (struct ethhdr *)skb->data;
++      if (ntohs(ethhdr->h_proto) == ETH_P_8021Q)
++              ethhdr = (struct ethhdr *)(skb->data + VLAN_HLEN);
++
+       udphdr = (struct udphdr *)(skb->data + *header_len);
+       *header_len += sizeof(*udphdr);
+@@ -634,12 +642,14 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
+       return true;
+ }
++/* this call might reallocate skb data */
+ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
+-                          struct sk_buff *skb, struct ethhdr *ethhdr)
++                          struct sk_buff *skb)
+ {
+       struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL;
+       struct batadv_orig_node *orig_dst_node = NULL;
+       struct batadv_gw_node *curr_gw = NULL;
++      struct ethhdr *ethhdr;
+       bool ret, out_of_range = false;
+       unsigned int header_len = 0;
+       uint8_t curr_tq_avg;
+@@ -648,6 +658,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
+       if (!ret)
+               goto out;
++      ethhdr = (struct ethhdr *)skb->data;
+       orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
+                                                ethhdr->h_dest);
+       if (!orig_dst_node)
+diff --git a/gateway_client.h b/gateway_client.h
+index 039902d..1037d75 100644
+--- a/gateway_client.h
++++ b/gateway_client.h
+@@ -34,7 +34,6 @@ void batadv_gw_node_delete(struct batadv_priv *bat_priv,
+ void batadv_gw_node_purge(struct batadv_priv *bat_priv);
+ int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset);
+ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len);
+-bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
+-                          struct sk_buff *skb, struct ethhdr *ethhdr);
++bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct sk_buff *skb);
+ #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */
+diff --git a/soft-interface.c b/soft-interface.c
+index 700d0b4..0f04e1c 100644
+--- a/soft-interface.c
++++ b/soft-interface.c
+@@ -180,6 +180,9 @@ static int batadv_interface_tx(struct sk_buff *skb,
+       if (batadv_bla_tx(bat_priv, skb, vid))
+               goto dropped;
++      /* skb->data might have been reallocated by batadv_bla_tx() */
++      ethhdr = (struct ethhdr *)skb->data;
++
+       /* Register the client MAC in the transtable */
+       if (!is_multicast_ether_addr(ethhdr->h_source))
+               batadv_tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif);
+@@ -220,6 +223,10 @@ static int batadv_interface_tx(struct sk_buff *skb,
+               default:
+                       break;
+               }
++
++              /* reminder: ethhdr might have become unusable from here on
++               * (batadv_gw_is_dhcp_target() might have reallocated skb data)
++               */
+       }
+       /* ethernet packet should be broadcasted */
+@@ -266,7 +273,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
+       /* unicast packet */
+       } else {
+               if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_OFF) {
+-                      ret = batadv_gw_out_of_range(bat_priv, skb, ethhdr);
++                      ret = batadv_gw_out_of_range(bat_priv, skb);
+                       if (ret)
+                               goto dropped;
+               }
+diff --git a/unicast.c b/unicast.c
+index dc8b5d4..688a041 100644
+--- a/unicast.c
++++ b/unicast.c
+@@ -326,7 +326,9 @@ static bool batadv_unicast_push_and_fill_skb(struct sk_buff *skb, int hdr_size,
+  * @skb: the skb containing the payload to encapsulate
+  * @orig_node: the destination node
+  *
+- * Returns false if the payload could not be encapsulated or true otherwise
++ * Returns false if the payload could not be encapsulated or true otherwise.
++ *
++ * This call might reallocate skb data.
+  */
+ static bool batadv_unicast_prepare_skb(struct sk_buff *skb,
+                                      struct batadv_orig_node *orig_node)
+@@ -343,7 +345,9 @@ static bool batadv_unicast_prepare_skb(struct sk_buff *skb,
+  * @orig_node: the destination node
+  * @packet_subtype: the batman 4addr packet subtype to use
+  *
+- * Returns false if the payload could not be encapsulated or true otherwise
++ * Returns false if the payload could not be encapsulated or true otherwise.
++ *
++ * This call might reallocate skb data.
+  */
+ bool batadv_unicast_4addr_prepare_skb(struct batadv_priv *bat_priv,
+                                     struct sk_buff *skb,
+@@ -401,7 +405,7 @@ int batadv_unicast_generic_send_skb(struct batadv_priv *bat_priv,
+       struct batadv_neigh_node *neigh_node;
+       int data_len = skb->len;
+       int ret = NET_RX_DROP;
+-      unsigned int dev_mtu;
++      unsigned int dev_mtu, header_len;
+       /* get routing information */
+       if (is_multicast_ether_addr(ethhdr->h_dest)) {
+@@ -429,10 +433,12 @@ find_router:
+       switch (packet_type) {
+       case BATADV_UNICAST:
+               batadv_unicast_prepare_skb(skb, orig_node);
++              header_len = sizeof(struct batadv_unicast_packet);
+               break;
+       case BATADV_UNICAST_4ADDR:
+               batadv_unicast_4addr_prepare_skb(bat_priv, skb, orig_node,
+                                                packet_subtype);
++              header_len = sizeof(struct batadv_unicast_4addr_packet);
+               break;
+       default:
+               /* this function supports UNICAST and UNICAST_4ADDR only. It
+@@ -441,6 +447,7 @@ find_router:
+               goto out;
+       }
++      ethhdr = (struct ethhdr *)(skb->data + header_len);
+       unicast_packet = (struct batadv_unicast_packet *)skb->data;
+       /* inform the destination node that we are still missing a correct route
+-- 
+1.7.10.4
+