mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
neighbour: fix data-races around n->output
n->output field can be read locklessly, while a writer
might change the pointer concurrently.
Add missing annotations to prevent load-store tearing.
Fixes: 1da177e4c3
("Linux-2.6.12-rc2")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
25563b581b
commit
5baa0433a1
@ -539,7 +539,7 @@ static inline int neigh_output(struct neighbour *n, struct sk_buff *skb,
|
||||
READ_ONCE(hh->hh_len))
|
||||
return neigh_hh_output(hh, skb);
|
||||
|
||||
return n->output(n, skb);
|
||||
return READ_ONCE(n->output)(n, skb);
|
||||
}
|
||||
|
||||
static inline struct neighbour *
|
||||
|
@ -294,7 +294,7 @@ int br_nf_pre_routing_finish_bridge(struct net *net, struct sock *sk, struct sk_
|
||||
/* tell br_dev_xmit to continue with forwarding */
|
||||
nf_bridge->bridged_dnat = 1;
|
||||
/* FIXME Need to refragment */
|
||||
ret = neigh->output(neigh, skb);
|
||||
ret = READ_ONCE(neigh->output)(neigh, skb);
|
||||
}
|
||||
neigh_release(neigh);
|
||||
return ret;
|
||||
|
@ -410,7 +410,7 @@ static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev,
|
||||
*/
|
||||
__skb_queue_purge(&n->arp_queue);
|
||||
n->arp_queue_len_bytes = 0;
|
||||
n->output = neigh_blackhole;
|
||||
WRITE_ONCE(n->output, neigh_blackhole);
|
||||
if (n->nud_state & NUD_VALID)
|
||||
n->nud_state = NUD_NOARP;
|
||||
else
|
||||
@ -920,7 +920,7 @@ static void neigh_suspect(struct neighbour *neigh)
|
||||
{
|
||||
neigh_dbg(2, "neigh %p is suspected\n", neigh);
|
||||
|
||||
neigh->output = neigh->ops->output;
|
||||
WRITE_ONCE(neigh->output, neigh->ops->output);
|
||||
}
|
||||
|
||||
/* Neighbour state is OK;
|
||||
@ -932,7 +932,7 @@ static void neigh_connect(struct neighbour *neigh)
|
||||
{
|
||||
neigh_dbg(2, "neigh %p is connected\n", neigh);
|
||||
|
||||
neigh->output = neigh->ops->connected_output;
|
||||
WRITE_ONCE(neigh->output, neigh->ops->connected_output);
|
||||
}
|
||||
|
||||
static void neigh_periodic_work(struct work_struct *work)
|
||||
@ -1449,7 +1449,7 @@ static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
|
||||
if (n2)
|
||||
n1 = n2;
|
||||
}
|
||||
n1->output(n1, skb);
|
||||
READ_ONCE(n1->output)(n1, skb);
|
||||
if (n2)
|
||||
neigh_release(n2);
|
||||
rcu_read_unlock();
|
||||
@ -3155,7 +3155,7 @@ int neigh_xmit(int index, struct net_device *dev,
|
||||
rcu_read_unlock();
|
||||
goto out_kfree_skb;
|
||||
}
|
||||
err = neigh->output(neigh, skb);
|
||||
err = READ_ONCE(neigh->output)(neigh, skb);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
else if (index == NEIGH_LINK_TABLE) {
|
||||
|
Loading…
Reference in New Issue
Block a user