From patchwork Tue Aug 6 14:15:32 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Linus_L=C3=BCssing?= X-Patchwork-Id: 3217 Return-Path: Received: from mout.web.de (mout.web.de [212.227.17.12]) by open-mesh.org (Postfix) with ESMTPS id 9C5A8601EFA for ; Tue, 6 Aug 2013 16:15:38 +0200 (CEST) Received: from localhost ([141.83.153.180]) by smtp.web.de (mrweb001) with ESMTPSA (Nemesis) id 0MgfXb-1VUALp1TvT-00O1r3 for ; Tue, 06 Aug 2013 16:15:37 +0200 From: =?UTF-8?q?Linus=20L=C3=BCssing?= To: b.a.t.m.a.n@lists.open-mesh.org Date: Tue, 6 Aug 2013 16:15:32 +0200 Message-Id: <1375798532-29520-1-git-send-email-linus.luessing@web.de> X-Mailer: git-send-email 1.8.3.2 MIME-Version: 1.0 X-Provags-ID: V03:K0:gMxIiYuUeTKaFuywEo+saWMwN05tOoWHqJB/3Szce316mw7A5Mg Tyt7h9GdVZ4GOukLbQNFfegb9Cza6uEldwEJmRkMWga+pScW32h3w69VAX1MZJ4iwdSw9PY NeTT4lGt6WFlFssgzw5k6E34UJyeHGkQAAnOP2DBSXFRRjV4QuxZldZOTs9nQaK/AxW62lf 8A6cC9SRsrohYtBAlEhTw== Subject: [B.A.T.M.A.N.] [PATCHv3 next] batman-adv: fix potential kernel paging errors for unicast transmissions X-BeenThere: b.a.t.m.a.n@lists.open-mesh.org X-Mailman-Version: 2.1.15 Precedence: list Reply-To: The list for a Better Approach To Mobile Ad-hoc Networking List-Id: The list for a Better Approach To Mobile Ad-hoc Networking List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 06 Aug 2013 14:15:39 -0000 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 --- v3: * Remove the change from 'Returns' to 'Return * Avoid using eth_hdr(skb), using (struct ethhdr *)skb->data instead * Added fix for batadv_gw_is_dhcp_target() too bridge_loop_avoidance.c | 2 ++ gateway_client.c | 12 +++++++++++- gateway_client.h | 3 +-- soft-interface.c | 8 +++++++- unicast.c | 9 +++++++-- 5 files changed, 28 insertions(+), 6 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..e1516d5 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,11 @@ 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; + + 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 +641,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 +657,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..b39e50d 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -180,6 +180,8 @@ static int batadv_interface_tx(struct sk_buff *skb, if (batadv_bla_tx(bat_priv, skb, vid)) goto dropped; + 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 +222,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 +272,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 4c5a1aa..7250b10 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, @@ -444,6 +448,7 @@ find_router: } unicast_packet = (struct batadv_unicast_packet *)skb->data; + ethhdr = (struct ethhdr *)skb->data; /* inform the destination node that we are still missing a correct route * for this client. The destination will receive this packet and will