Skip to content

Commit

Permalink
Merge tag 'batman-adv-fix-for-davem' of git://git.open-mesh.org/linux…
Browse files Browse the repository at this point in the history
…-merge

Included change:
- reassign pointers to data after skb reallocation to avoid kernel paging errors

Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
davem330 committed Aug 10, 2013
2 parents 4209423 + 9d2c948 commit e5ac5da
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 7 deletions.
2 changes: 2 additions & 0 deletions net/batman-adv/bridge_loop_avoidance.c
Original file line number Diff line number Diff line change
Expand Up @@ -1529,6 +1529,8 @@ int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb,
* 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)
Expand Down
13 changes: 12 additions & 1 deletion net/batman-adv/gateway_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,7 @@ int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset)
return 0;
}

/* this call might reallocate skb data */
static bool batadv_is_type_dhcprequest(struct sk_buff *skb, int header_len)
{
int ret = false;
Expand Down Expand Up @@ -568,6 +569,7 @@ static bool batadv_is_type_dhcprequest(struct sk_buff *skb, int header_len)
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;
Expand Down Expand Up @@ -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);

Expand All @@ -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;
Expand All @@ -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)
Expand Down
3 changes: 1 addition & 2 deletions net/batman-adv/gateway_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_ */
9 changes: 8 additions & 1 deletion net/batman-adv/soft-interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
}
Expand Down
13 changes: 10 additions & 3 deletions net/batman-adv/unicast.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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,
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -429,10 +433,12 @@ int batadv_unicast_generic_send_skb(struct batadv_priv *bat_priv,
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
Expand All @@ -441,6 +447,7 @@ int batadv_unicast_generic_send_skb(struct batadv_priv *bat_priv,
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
Expand Down

0 comments on commit e5ac5da

Please sign in to comment.