提交 9d2c9488 编写于 作者: L Linus Lüssing 提交者: Antonio Quartulli

batman-adv: fix potential kernel paging errors for unicast transmissions

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: NLinus Lüssing <linus.luessing@web.de>
Signed-off-by: NMarek Lindner <lindner_marek@yahoo.de>
Signed-off-by: NAntonio Quartulli <ordex@autistici.org>
上级 64535993
...@@ -1529,6 +1529,8 @@ int batadv_bla_rx(struct batadv_priv *bat_priv, struct sk_buff *skb, ...@@ -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 * in these cases, the skb is further handled by this function and
* returns 1, otherwise it returns 0 and the caller shall further * returns 1, otherwise it returns 0 and the caller shall further
* process the skb. * process the skb.
*
* This call might reallocate skb data.
*/ */
int batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb, int batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb,
unsigned short vid) unsigned short vid)
......
...@@ -508,6 +508,7 @@ int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset) ...@@ -508,6 +508,7 @@ int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset)
return 0; return 0;
} }
/* this call might reallocate skb data */
static bool batadv_is_type_dhcprequest(struct sk_buff *skb, int header_len) static bool batadv_is_type_dhcprequest(struct sk_buff *skb, int header_len)
{ {
int ret = false; int ret = false;
...@@ -568,6 +569,7 @@ static bool batadv_is_type_dhcprequest(struct sk_buff *skb, int header_len) ...@@ -568,6 +569,7 @@ static bool batadv_is_type_dhcprequest(struct sk_buff *skb, int header_len)
return ret; return ret;
} }
/* this call might reallocate skb data */
bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len) bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
{ {
struct ethhdr *ethhdr; struct ethhdr *ethhdr;
...@@ -619,6 +621,12 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len) ...@@ -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))) if (!pskb_may_pull(skb, *header_len + sizeof(*udphdr)))
return false; 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); udphdr = (struct udphdr *)(skb->data + *header_len);
*header_len += sizeof(*udphdr); *header_len += sizeof(*udphdr);
...@@ -634,12 +642,14 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len) ...@@ -634,12 +642,14 @@ bool batadv_gw_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len)
return true; return true;
} }
/* this call might reallocate skb data */
bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, 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_neigh_node *neigh_curr = NULL, *neigh_old = NULL;
struct batadv_orig_node *orig_dst_node = NULL; struct batadv_orig_node *orig_dst_node = NULL;
struct batadv_gw_node *curr_gw = NULL; struct batadv_gw_node *curr_gw = NULL;
struct ethhdr *ethhdr;
bool ret, out_of_range = false; bool ret, out_of_range = false;
unsigned int header_len = 0; unsigned int header_len = 0;
uint8_t curr_tq_avg; uint8_t curr_tq_avg;
...@@ -648,6 +658,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, ...@@ -648,6 +658,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
if (!ret) if (!ret)
goto out; goto out;
ethhdr = (struct ethhdr *)skb->data;
orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source, orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
ethhdr->h_dest); ethhdr->h_dest);
if (!orig_dst_node) if (!orig_dst_node)
......
...@@ -34,7 +34,6 @@ void batadv_gw_node_delete(struct batadv_priv *bat_priv, ...@@ -34,7 +34,6 @@ void batadv_gw_node_delete(struct batadv_priv *bat_priv,
void batadv_gw_node_purge(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); 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_is_dhcp_target(struct sk_buff *skb, unsigned int *header_len);
bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct sk_buff *skb);
struct sk_buff *skb, struct ethhdr *ethhdr);
#endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */ #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */
...@@ -180,6 +180,9 @@ static int batadv_interface_tx(struct sk_buff *skb, ...@@ -180,6 +180,9 @@ static int batadv_interface_tx(struct sk_buff *skb,
if (batadv_bla_tx(bat_priv, skb, vid)) if (batadv_bla_tx(bat_priv, skb, vid))
goto dropped; goto dropped;
/* skb->data might have been reallocated by batadv_bla_tx() */
ethhdr = (struct ethhdr *)skb->data;
/* Register the client MAC in the transtable */ /* Register the client MAC in the transtable */
if (!is_multicast_ether_addr(ethhdr->h_source)) if (!is_multicast_ether_addr(ethhdr->h_source))
batadv_tt_local_add(soft_iface, ethhdr->h_source, skb->skb_iif); 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, ...@@ -220,6 +223,10 @@ static int batadv_interface_tx(struct sk_buff *skb,
default: default:
break; 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 */ /* ethernet packet should be broadcasted */
...@@ -266,7 +273,7 @@ static int batadv_interface_tx(struct sk_buff *skb, ...@@ -266,7 +273,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
/* unicast packet */ /* unicast packet */
} else { } else {
if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_OFF) { 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) if (ret)
goto dropped; goto dropped;
} }
......
...@@ -326,7 +326,9 @@ static bool batadv_unicast_push_and_fill_skb(struct sk_buff *skb, int hdr_size, ...@@ -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 * @skb: the skb containing the payload to encapsulate
* @orig_node: the destination node * @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, static bool batadv_unicast_prepare_skb(struct sk_buff *skb,
struct batadv_orig_node *orig_node) struct batadv_orig_node *orig_node)
...@@ -343,7 +345,9 @@ static bool batadv_unicast_prepare_skb(struct sk_buff *skb, ...@@ -343,7 +345,9 @@ static bool batadv_unicast_prepare_skb(struct sk_buff *skb,
* @orig_node: the destination node * @orig_node: the destination node
* @packet_subtype: the batman 4addr packet subtype to use * @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, bool batadv_unicast_4addr_prepare_skb(struct batadv_priv *bat_priv,
struct sk_buff *skb, struct sk_buff *skb,
...@@ -401,7 +405,7 @@ int batadv_unicast_generic_send_skb(struct batadv_priv *bat_priv, ...@@ -401,7 +405,7 @@ int batadv_unicast_generic_send_skb(struct batadv_priv *bat_priv,
struct batadv_neigh_node *neigh_node; struct batadv_neigh_node *neigh_node;
int data_len = skb->len; int data_len = skb->len;
int ret = NET_RX_DROP; int ret = NET_RX_DROP;
unsigned int dev_mtu; unsigned int dev_mtu, header_len;
/* get routing information */ /* get routing information */
if (is_multicast_ether_addr(ethhdr->h_dest)) { if (is_multicast_ether_addr(ethhdr->h_dest)) {
...@@ -429,10 +433,12 @@ int batadv_unicast_generic_send_skb(struct batadv_priv *bat_priv, ...@@ -429,10 +433,12 @@ int batadv_unicast_generic_send_skb(struct batadv_priv *bat_priv,
switch (packet_type) { switch (packet_type) {
case BATADV_UNICAST: case BATADV_UNICAST:
batadv_unicast_prepare_skb(skb, orig_node); batadv_unicast_prepare_skb(skb, orig_node);
header_len = sizeof(struct batadv_unicast_packet);
break; break;
case BATADV_UNICAST_4ADDR: case BATADV_UNICAST_4ADDR:
batadv_unicast_4addr_prepare_skb(bat_priv, skb, orig_node, batadv_unicast_4addr_prepare_skb(bat_priv, skb, orig_node,
packet_subtype); packet_subtype);
header_len = sizeof(struct batadv_unicast_4addr_packet);
break; break;
default: default:
/* this function supports UNICAST and UNICAST_4ADDR only. It /* this function supports UNICAST and UNICAST_4ADDR only. It
...@@ -441,6 +447,7 @@ int batadv_unicast_generic_send_skb(struct batadv_priv *bat_priv, ...@@ -441,6 +447,7 @@ int batadv_unicast_generic_send_skb(struct batadv_priv *bat_priv,
goto out; goto out;
} }
ethhdr = (struct ethhdr *)(skb->data + header_len);
unicast_packet = (struct batadv_unicast_packet *)skb->data; unicast_packet = (struct batadv_unicast_packet *)skb->data;
/* inform the destination node that we are still missing a correct route /* inform the destination node that we are still missing a correct route
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册