Hello David,
here you have a pull request intended for net/linux-3.14 and linux-3.13 (please take care of queuing these patches for merging in the latter).
Patch 1 fixes the computation of the MTU assigned to a soft-interface. This value is based on the MTUs of the real interfaces handled by batman-adv and due to an arithmetical error the result was always smaller than what it was supposed to be.
Patch 2 fixes the access to a TT TVLV message in the RX path this avoiding to read random memory. This bug was leading to a bogus TT update messages parsing, thus to a continuous generation of useless traffic needed to recover the entire table from another node in the network.
Patch 3 is fixing a memory leak caused by a reference counting unbalance: after having used a VLAN object to compare its CRC with the value received by another node, the reference counter was never decreased so preventing the object to be free'd when needed.
Patch 4 is a minor fix which properly addresses a wrong assumption on the pskb_may_pull return value.
Patch 5 fixes a potential race condition when adding a new neighbour.
Patch 6 fixes a potential memory leak that could be triggered in case of failure of the originator node initialization routine by Simon Wunderlich.
Patch 7 fixes the TranslationTable CRC computation (used for consistency check) by taking into consideration the endianess of the host machine. Prior to this fix, hosts having different endianess would compute different CRCs thus continuously triggering an "inconsistency" exception with respect to the received data which resulted in an endless sequence of recovery messages.
Patch 8 fixes a severe memory leak caused by a missing SKB consumption after a successful TVLV message parsing.
Patch 9 avoids a potential double free that could be trigger in case of orig_node initialization failure.
Patch 10 fixes a potential kernel paging error caused by the wrong usage of an old skb->data pointer after that the skb itself was reallocated (by pskb_may_pull()) by me in collaboration with Linus Lüssing.
Please pull or let me know of any problem!
Thanks a lot, Antonio
The following changes since commit 0fd5d57ba3456c4d0b77d1ae64be4818b47d7545:
packet: check for ndo_select_queue during queue selection (2014-02-17 00:36:34 -0500)
are available in the git repository at:
git://git.open-mesh.org/linux-merge.git tags/batman-adv-fix-for-davem
for you to fetch changes up to 70b271a78beba787155d6696aacd7c4d4a251c50:
batman-adv: fix potential kernel paging error for unicast transmissions (2014-02-17 17:17:02 +0100)
---------------------------------------------------------------- Included changes: - fix soft-interface MTU computation - fix bogus pointer mangling when parsing the TT-TVLV container. This bug led to a wrong memory access. - fix memory leak by properly releasing the VLAN object after CRC check - properly check pskb_may_pull() return value - avoid potential race condition while adding new neighbour - fix potential memory leak by removing all the references to the orig_node object in case of initialization failure - fix the TT CRC computation by ensuring that every node uses the same byte order when hosts with different endianess are part of the same network - fix severe memory leak by freeing skb after a successful TVLV parsing - avoid potential double free when orig_node initialization fails - fix potential kernel paging error caused by the usage of the old value of skb->data after skb reallocation
---------------------------------------------------------------- Antonio Quartulli (9): batman-adv: fix soft-interface MTU computation batman-adv: fix TT-TVLV parsing on OGM reception batman-adv: release vlan object after checking the CRC batman-adv: properly check pskb_may_pull return value batman-adv: avoid potential race condition when adding a new neighbour batman-adv: fix TT CRC computation by ensuring byte order batman-adv: free skb on TVLV parsing success batman-adv: avoid double free when orig_node initialization fails batman-adv: fix potential kernel paging error for unicast transmissions
Simon Wunderlich (1): batman-adv: fix potential orig_node reference leak
net/batman-adv/bat_iv_ogm.c | 30 ++++++++++++++++++++---------- net/batman-adv/hard-interface.c | 22 ++++++++++++++-------- net/batman-adv/originator.c | 36 ++++++++++++++++++++++++++++++++++++ net/batman-adv/originator.h | 4 ++++ net/batman-adv/routing.c | 4 +++- net/batman-adv/send.c | 9 +++++++-- net/batman-adv/translation-table.c | 23 +++++++++++++++++------ 7 files changed, 101 insertions(+), 27 deletions(-)
The current MTU computation always returns a value smaller than 1500bytes even if the real interfaces have an MTU large enough to compensate the batman-adv overhead.
Fix the computation by properly returning the highest admitted value.
Introduced by a19d3d85e1b854e4a483a55d740a42458085560d ("batman-adv: limit local translation table max size")
Reported-by: Russell Senior russell@personaltelco.net Signed-off-by: Antonio Quartulli antonio@meshcoding.com Signed-off-by: Marek Lindner mareklindner@neomailbox.ch --- net/batman-adv/hard-interface.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index 3d417d3..b851cc5 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -241,7 +241,7 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface) { struct batadv_priv *bat_priv = netdev_priv(soft_iface); const struct batadv_hard_iface *hard_iface; - int min_mtu = ETH_DATA_LEN; + int min_mtu = INT_MAX;
rcu_read_lock(); list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { @@ -256,8 +256,6 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface) } rcu_read_unlock();
- atomic_set(&bat_priv->packet_size_max, min_mtu); - if (atomic_read(&bat_priv->fragmentation) == 0) goto out;
@@ -268,13 +266,21 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface) min_mtu = min_t(int, min_mtu, BATADV_FRAG_MAX_FRAG_SIZE); min_mtu -= sizeof(struct batadv_frag_packet); min_mtu *= BATADV_FRAG_MAX_FRAGMENTS; - atomic_set(&bat_priv->packet_size_max, min_mtu); - - /* with fragmentation enabled we can fragment external packets easily */ - min_mtu = min_t(int, min_mtu, ETH_DATA_LEN);
out: - return min_mtu - batadv_max_header_len(); + /* report to the other components the maximum amount of bytes that + * batman-adv can send over the wire (without considering the payload + * overhead). For example, this value is used by TT to compute the + * maximum local table table size + */ + atomic_set(&bat_priv->packet_size_max, min_mtu); + + /* the real soft-interface MTU is computed by removing the payload + * overhead from the maximum amount of bytes that was just computed. + * + * However batman-adv does not support MTUs bigger than ETH_DATA_LEN + */ + return min_t(int, min_mtu - batadv_max_header_len(), ETH_DATA_LEN); }
/* adjusts the MTU if a new interface with a smaller MTU appeared. */
From: Antonio Quartulli antonio@meshcoding.com Date: Mon, 17 Feb 2014 21:48:40 +0100
- atomic_set(&bat_priv->packet_size_max, min_mtu);
Please fix this.
The only operations performed on packet_size_max are 'set' and 'read'. This is not what one uses atomic_t's for.
The use of an atomic_t in this context is a NOP. You aren't getting any kind of synchronization at all.
On 17/02/14 22:13, David Miller wrote:
From: Antonio Quartulli antonio@meshcoding.com Date: Mon, 17 Feb 2014 21:48:40 +0100
- atomic_set(&bat_priv->packet_size_max, min_mtu);
Please fix this.
The only operations performed on packet_size_max are 'set' and 'read'. This is not what one uses atomic_t's for.
The use of an atomic_t in this context is a NOP. You aren't getting any kind of synchronization at all.
True. Thanks for the suggestion. Unfortunately this is not the only "fake-atomic" variable we have.
We'll send a change for this later within our pull request for net-next, ok?
From: Antonio Quartulli antonio@meshcoding.com Date: Tue, 18 Feb 2014 07:44:53 +0100
Unfortunately this is not the only "fake-atomic" variable we have.
:-(
We'll send a change for this later within our pull request for net-next, ok?
Fair enough.
From: Antonio Quartulli antonio@meshcoding.com Date: Tue, 18 Feb 2014 07:44:53 +0100
On 17/02/14 22:13, David Miller wrote:
From: Antonio Quartulli antonio@meshcoding.com Date: Mon, 17 Feb 2014 21:48:40 +0100
- atomic_set(&bat_priv->packet_size_max, min_mtu);
Please fix this.
The only operations performed on packet_size_max are 'set' and 'read'. This is not what one uses atomic_t's for.
The use of an atomic_t in this context is a NOP. You aren't getting any kind of synchronization at all.
True. Thanks for the suggestion. Unfortunately this is not the only "fake-atomic" variable we have.
So I pulled this, but I just want you to know that you should really start to bear down and minimize the amount of changes you are submitting for 'net' as we're starting to get deep into -rc territory.
Thanks.
On 18/02/14 21:41, David Miller wrote:
So I pulled this, but I just want you to know that you should really start to bear down and minimize the amount of changes you are submitting for 'net' as we're starting to get deep into -rc territory.
I decided to wait until the last bugfix was ready before sending the patchset....but I imagine a better choice is to send the big bunch as soon as possible and then keep the small remaining bits for later.
I will do that next time. Thanks!
When accessing a TT-TVLV container in the OGM RX path the variable pointing to the list of changes to apply is altered by mistake.
This makes the TT component read data at the wrong position in the OGM packet buffer.
Fix it by removing the bogus pointer alteration.
Signed-off-by: Antonio Quartulli antonio@meshcoding.com Signed-off-by: Marek Lindner mareklindner@neomailbox.ch --- net/batman-adv/translation-table.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index b6071f6..beba13f 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -3218,7 +3218,6 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv,
spin_lock_bh(&orig_node->tt_lock);
- tt_change = (struct batadv_tvlv_tt_change *)tt_buff; batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn, tt_change);
There is a refcounter unbalance in the CRC checking routine invoked on OGM reception. A vlan object is retrieved (thus its refcounter is increased by one) but it is never properly released. This leads to a memleak because the vlan object will never be free'd.
Fix this by releasing the vlan object after having read the CRC.
Reported-by: Russell Senior russell@personaltelco.net Reported-by: Daniel daniel@makrotopia.org Reported-by: cmsv cmsv@wirelesspt.net Signed-off-by: Antonio Quartulli antonio@meshcoding.com Signed-off-by: Marek Lindner mareklindner@neomailbox.ch --- net/batman-adv/translation-table.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index beba13f..c21c557 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -2262,6 +2262,7 @@ static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node, { struct batadv_tvlv_tt_vlan_data *tt_vlan_tmp; struct batadv_orig_node_vlan *vlan; + uint32_t crc; int i;
/* check if each received CRC matches the locally stored one */ @@ -2281,7 +2282,10 @@ static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node, if (!vlan) return false;
- if (vlan->tt.crc != ntohl(tt_vlan_tmp->crc)) + crc = vlan->tt.crc; + batadv_orig_node_vlan_free_ref(vlan); + + if (crc != ntohl(tt_vlan_tmp->crc)) return false; }
pskb_may_pull() returns 1 on success and 0 in case of failure, therefore checking for the return value being negative does not make sense at all.
This way if the function fails we will probably read beyond the current skb data buffer. Fix this by doing the proper check.
Signed-off-by: Antonio Quartulli antonio@meshcoding.com Signed-off-by: Marek Lindner mareklindner@neomailbox.ch --- net/batman-adv/routing.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 1ed9f7c..c26f073 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -688,7 +688,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, int is_old_ttvn;
/* check if there is enough data before accessing it */ - if (pskb_may_pull(skb, hdr_len + ETH_HLEN) < 0) + if (!pskb_may_pull(skb, hdr_len + ETH_HLEN)) return 0;
/* create a copy of the skb (in case of for re-routing) to modify it. */
From: Antonio Quartulli antonio@open-mesh.com
When adding a new neighbour it is important to atomically perform the following: - check if the neighbour already exists - append the neighbour to the proper list
If the two operations are not performed in an atomic context it is possible that two concurrent insertions add the same neighbour twice.
Signed-off-by: Antonio Quartulli antonio@open-mesh.com Signed-off-by: Marek Lindner mareklindner@neomailbox.ch --- net/batman-adv/bat_iv_ogm.c | 22 ++++++++++++++++------ net/batman-adv/originator.c | 36 ++++++++++++++++++++++++++++++++++++ net/batman-adv/originator.h | 4 ++++ 3 files changed, 56 insertions(+), 6 deletions(-)
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 512159b..094ae7c 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -266,7 +266,7 @@ batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface, struct batadv_orig_node *orig_neigh) { struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); - struct batadv_neigh_node *neigh_node; + struct batadv_neigh_node *neigh_node, *tmp_neigh_node;
neigh_node = batadv_neigh_node_new(hard_iface, neigh_addr, orig_node); if (!neigh_node) @@ -281,14 +281,24 @@ batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface, neigh_node->orig_node = orig_neigh; neigh_node->if_incoming = hard_iface;
- batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "Creating new neighbor %pM for orig_node %pM on interface %s\n", - neigh_addr, orig_node->orig, hard_iface->net_dev->name); - spin_lock_bh(&orig_node->neigh_list_lock); - hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list); + tmp_neigh_node = batadv_neigh_node_get(orig_node, hard_iface, + neigh_addr); + if (!tmp_neigh_node) { + hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list); + } else { + kfree(neigh_node); + batadv_hardif_free_ref(hard_iface); + neigh_node = tmp_neigh_node; + } spin_unlock_bh(&orig_node->neigh_list_lock);
+ if (!tmp_neigh_node) + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Creating new neighbor %pM for orig_node %pM on interface %s\n", + neigh_addr, orig_node->orig, + hard_iface->net_dev->name); + out: return neigh_node; } diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 6df12a2..8539416 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -458,6 +458,42 @@ out: }
/** + * batadv_neigh_node_get - retrieve a neighbour from the list + * @orig_node: originator which the neighbour belongs to + * @hard_iface: the interface where this neighbour is connected to + * @addr: the address of the neighbour + * + * Looks for and possibly returns a neighbour belonging to this originator list + * which is connected through the provided hard interface. + * Returns NULL if the neighbour is not found. + */ +struct batadv_neigh_node * +batadv_neigh_node_get(const struct batadv_orig_node *orig_node, + const struct batadv_hard_iface *hard_iface, + const uint8_t *addr) +{ + struct batadv_neigh_node *tmp_neigh_node, *res = NULL; + + rcu_read_lock(); + hlist_for_each_entry_rcu(tmp_neigh_node, &orig_node->neigh_list, list) { + if (!batadv_compare_eth(tmp_neigh_node->addr, addr)) + continue; + + if (tmp_neigh_node->if_incoming != hard_iface) + continue; + + if (!atomic_inc_not_zero(&tmp_neigh_node->refcount)) + continue; + + res = tmp_neigh_node; + break; + } + rcu_read_unlock(); + + return res; +} + +/** * batadv_orig_ifinfo_free_rcu - free the orig_ifinfo object * @rcu: rcu pointer of the orig_ifinfo object */ diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index 37be290..db3a9ed 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h @@ -29,6 +29,10 @@ void batadv_orig_node_free_ref_now(struct batadv_orig_node *orig_node); struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, const uint8_t *addr); struct batadv_neigh_node * +batadv_neigh_node_get(const struct batadv_orig_node *orig_node, + const struct batadv_hard_iface *hard_iface, + const uint8_t *addr); +struct batadv_neigh_node * batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, const uint8_t *neigh_addr, struct batadv_orig_node *orig_node);
From: Simon Wunderlich sw@simonwunderlich.de
Since batadv_orig_node_new() sets the refcount to two, assuming that the calling function will use a reference for putting the orig_node into a hash or similar, both references must be freed if initialization of the orig_node fails. Otherwise that object may be leaked in that error case.
Reported-by: Antonio Quartulli antonio@meshcoding.com Signed-off-by: Simon Wunderlich sw@simonwunderlich.de Signed-off-by: Marek Lindner mareklindner@neomailbox.ch Signed-off-by: Antonio Quartulli antonio@meshcoding.com --- net/batman-adv/bat_iv_ogm.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 094ae7c..42cbc0a 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -254,6 +254,8 @@ batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const uint8_t *addr) free_bcast_own: kfree(orig_node->bat_iv.bcast_own); free_orig_node: + /* free twice, as batadv_orig_node_new sets refcount to 2 */ + batadv_orig_node_free_ref(orig_node); batadv_orig_node_free_ref(orig_node);
return NULL;
From: Antonio Quartulli antonio@open-mesh.com
When computing the CRC on a 2byte variable the order of the bytes obviously alters the final result. This means that computing the CRC over the same value on two archs having different endianess leads to different numbers.
The global and local translation table CRC computation routine makes this mistake while processing the clients VIDs. The result is a continuous CRC mismatching between nodes having different endianess.
Fix this by converting the VID to Network Order before processing it. This guarantees that every node uses the same byte order.
Introduced by 7ea7b4a142758deaf46c1af0ca9ceca6dd55138b ("batman-adv: make the TT CRC logic VLAN specific")
Reported-by: Russel Senior russell@personaltelco.net Signed-off-by: Antonio Quartulli antonio@open-mesh.com Tested-by: Russell Senior russell@personaltelco.net Signed-off-by: Marek Lindner mareklindner@neomailbox.ch --- net/batman-adv/translation-table.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index c21c557..959dde7 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -1975,6 +1975,7 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv, struct hlist_head *head; uint32_t i, crc_tmp, crc = 0; uint8_t flags; + __be16 tmp_vid;
for (i = 0; i < hash->size; i++) { head = &hash->table[i]; @@ -2011,8 +2012,11 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv, orig_node)) continue;
- crc_tmp = crc32c(0, &tt_common->vid, - sizeof(tt_common->vid)); + /* use network order to read the VID: this ensures that + * every node reads the bytes in the same order. + */ + tmp_vid = htons(tt_common->vid); + crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid));
/* compute the CRC on flags that have to be kept in sync * among nodes @@ -2046,6 +2050,7 @@ static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv, struct hlist_head *head; uint32_t i, crc_tmp, crc = 0; uint8_t flags; + __be16 tmp_vid;
for (i = 0; i < hash->size; i++) { head = &hash->table[i]; @@ -2064,8 +2069,11 @@ static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv, if (tt_common->flags & BATADV_TT_CLIENT_NEW) continue;
- crc_tmp = crc32c(0, &tt_common->vid, - sizeof(tt_common->vid)); + /* use network order to read the VID: this ensures that + * every node reads the bytes in the same order. + */ + tmp_vid = htons(tt_common->vid); + crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid));
/* compute the CRC on flags that have to be kept in sync * among nodes
From: Antonio Quartulli antonio@open-mesh.com
When the TVLV parsing routine succeed the skb is left untouched thus leading to a memory leak.
Fix this by consuming the skb in case of success.
Introduced by ef26157747d42254453f6b3ac2bd8bd3c53339c3 ("batman-adv: tvlv - basic infrastructure")
Reported-by: Russel Senior russell@personaltelco.net Signed-off-by: Antonio Quartulli antonio@open-mesh.com Tested-by: Russell Senior russell@personaltelco.net Signed-off-by: Marek Lindner mareklindner@neomailbox.ch --- net/batman-adv/routing.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index c26f073..a953d5b 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -918,6 +918,8 @@ int batadv_recv_unicast_tvlv(struct sk_buff *skb,
if (ret != NET_RX_SUCCESS) ret = batadv_route_unicast_packet(skb, recv_if); + else + consume_skb(skb);
return ret; }
In the failure path of the orig_node initialization routine the orig_node->bat_iv.bcast_own field is free'd twice: first in batadv_iv_ogm_orig_get() and then later in batadv_orig_node_free_rcu().
Fix it by removing the kfree in batadv_iv_ogm_orig_get().
Signed-off-by: Antonio Quartulli antonio@meshcoding.com Signed-off-by: Marek Lindner mareklindner@neomailbox.ch --- net/batman-adv/bat_iv_ogm.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 42cbc0a..8323bce 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -241,18 +241,16 @@ batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const uint8_t *addr) size = bat_priv->num_ifaces * sizeof(uint8_t); orig_node->bat_iv.bcast_own_sum = kzalloc(size, GFP_ATOMIC); if (!orig_node->bat_iv.bcast_own_sum) - goto free_bcast_own; + goto free_orig_node;
hash_added = batadv_hash_add(bat_priv->orig_hash, batadv_compare_orig, batadv_choose_orig, orig_node, &orig_node->hash_entry); if (hash_added != 0) - goto free_bcast_own; + goto free_orig_node;
return orig_node;
-free_bcast_own: - kfree(orig_node->bat_iv.bcast_own); free_orig_node: /* free twice, as batadv_orig_node_new sets refcount to 2 */ batadv_orig_node_free_ref(orig_node);
batadv_send_skb_prepare_unicast(_4addr) might reallocate the skb's data. If it does then our ethhdr pointer is not valid anymore in batadv_send_skb_unicast(), resulting in a kernel paging error.
Fixing this by refetching the ethhdr pointer after the potential reallocation.
Signed-off-by: Linus Lüssing linus.luessing@web.de Signed-off-by: Antonio Quartulli antonio@meshcoding.com --- net/batman-adv/send.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index 579f5f0..843febd 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -254,9 +254,9 @@ static int batadv_send_skb_unicast(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, unsigned short vid) { - struct ethhdr *ethhdr = (struct ethhdr *)skb->data; + struct ethhdr *ethhdr; struct batadv_unicast_packet *unicast_packet; - int ret = NET_XMIT_DROP; + int ret = NET_XMIT_DROP, hdr_size;
if (!orig_node) goto out; @@ -265,12 +265,16 @@ static int batadv_send_skb_unicast(struct batadv_priv *bat_priv, case BATADV_UNICAST: if (!batadv_send_skb_prepare_unicast(skb, orig_node)) goto out; + + hdr_size = sizeof(*unicast_packet); break; case BATADV_UNICAST_4ADDR: if (!batadv_send_skb_prepare_unicast_4addr(bat_priv, skb, orig_node, packet_subtype)) goto out; + + hdr_size = sizeof(struct batadv_unicast_4addr_packet); break; default: /* this function supports UNICAST and UNICAST_4ADDR only. It @@ -279,6 +283,7 @@ static int batadv_send_skb_unicast(struct batadv_priv *bat_priv, goto out; }
+ ethhdr = (struct ethhdr *)(skb->data + hdr_size); unicast_packet = (struct batadv_unicast_packet *)skb->data;
/* inform the destination node that we are still missing a correct route
On 17/02/14 21:48, Antonio Quartulli wrote:
Hello David,
here you have a pull request intended for net/linux-3.14 and linux-3.13 (please take care of queuing these patches for merging in the latter).
David,
as I asked above, do you think it would be possible to queue this patchset for inclusion in 3.13.x ?
If you think the patchset is too big, we can safely _exclude_ patches 4, 5, 6 and 9 from sending to stable since they are fixing "potential" errors.
Thanks a lot!
From: Antonio Quartulli antonio@meshcoding.com Date: Fri, 21 Feb 2014 08:47:20 +0100
as I asked above, do you think it would be possible to queue this patchset for inclusion in 3.13.x ?
Done.
b.a.t.m.a.n@lists.open-mesh.org