Skip to content

Commit 859828c

Browse files
jpirkodavem330
authored andcommitted
br: fix use of ->rx_handler_data in code executed on non-rx_handler path
br_stp_rcv() is reached by non-rx_handler path. That means there is no guarantee that dev is bridge port and therefore simple NULL check of ->rx_handler_data is not enough. There is need to check if dev is really bridge port and since only rcu read lock is held here, do it by checking ->rx_handler pointer. Note that synchronize_net() in netdev_rx_handler_unregister() ensures this approach as valid. Introduced originally by: commit f350a0a "bridge: use rx_handler_data pointer to store net_bridge_port pointer" Fixed but not in the best way by: commit b5ed54e "bridge: fix RCU races with bridge port" Reintroduced by: commit 716ec05 "bridge: fix NULL pointer deref of br_port_get_rcu" Please apply to stable trees as well. Thanks. RH bugzilla reference: https://bugzilla.redhat.com/show_bug.cgi?id=1025770 Reported-by: Laine Stump <[email protected]> Debugged-by: Michael S. Tsirkin <[email protected]> Signed-off-by: Michael S. Tsirkin <[email protected]> Signed-off-by: Jiri Pirko <[email protected]> Acked-by: Michael S. Tsirkin <[email protected]> Acked-by: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d4fb84e commit 859828c

File tree

2 files changed

+11
-1
lines changed

2 files changed

+11
-1
lines changed

net/bridge/br_private.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,16 @@ netdev_features_t br_features_recompute(struct net_bridge *br,
426426
int br_handle_frame_finish(struct sk_buff *skb);
427427
rx_handler_result_t br_handle_frame(struct sk_buff **pskb);
428428

429+
static inline bool br_rx_handler_check_rcu(const struct net_device *dev)
430+
{
431+
return rcu_dereference(dev->rx_handler) == br_handle_frame;
432+
}
433+
434+
static inline struct net_bridge_port *br_port_get_check_rcu(const struct net_device *dev)
435+
{
436+
return br_rx_handler_check_rcu(dev) ? br_port_get_rcu(dev) : NULL;
437+
}
438+
429439
/* br_ioctl.c */
430440
int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
431441
int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd,

net/bridge/br_stp_bpdu.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb,
153153
if (buf[0] != 0 || buf[1] != 0 || buf[2] != 0)
154154
goto err;
155155

156-
p = br_port_get_rcu(dev);
156+
p = br_port_get_check_rcu(dev);
157157
if (!p)
158158
goto err;
159159

0 commit comments

Comments
 (0)