bridge: Partially disable netpoll support
The new netpoll code in bridging contains use-after-free bugs that are non-trivial to fix. This patch fixes this by removing the code that uses skbs after they're freed. As a consequence, this means that we can no longer call bridge from the netpoll path, so this patch also removes the controller function in order to disable netpoll. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Thanks, Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
45e77d3145
commit
573201f36f
@@ -217,14 +217,6 @@ static bool br_devices_support_netpoll(struct net_bridge *br)
|
|||||||
return count != 0 && ret;
|
return count != 0 && ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void br_poll_controller(struct net_device *br_dev)
|
|
||||||
{
|
|
||||||
struct netpoll *np = br_dev->npinfo->netpoll;
|
|
||||||
|
|
||||||
if (np->real_dev != br_dev)
|
|
||||||
netpoll_poll_dev(np->real_dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
void br_netpoll_cleanup(struct net_device *dev)
|
void br_netpoll_cleanup(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct net_bridge *br = netdev_priv(dev);
|
struct net_bridge *br = netdev_priv(dev);
|
||||||
@@ -295,7 +287,6 @@ static const struct net_device_ops br_netdev_ops = {
|
|||||||
.ndo_do_ioctl = br_dev_ioctl,
|
.ndo_do_ioctl = br_dev_ioctl,
|
||||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||||
.ndo_netpoll_cleanup = br_netpoll_cleanup,
|
.ndo_netpoll_cleanup = br_netpoll_cleanup,
|
||||||
.ndo_poll_controller = br_poll_controller,
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -50,14 +50,7 @@ int br_dev_queue_push_xmit(struct sk_buff *skb)
|
|||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
else {
|
else {
|
||||||
skb_push(skb, ETH_HLEN);
|
skb_push(skb, ETH_HLEN);
|
||||||
|
dev_queue_xmit(skb);
|
||||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
|
||||||
if (unlikely(skb->dev->priv_flags & IFF_IN_NETPOLL)) {
|
|
||||||
netpoll_send_skb(skb->dev->npinfo->netpoll, skb);
|
|
||||||
skb->dev->priv_flags &= ~IFF_IN_NETPOLL;
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
dev_queue_xmit(skb);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,23 +66,9 @@ int br_forward_finish(struct sk_buff *skb)
|
|||||||
|
|
||||||
static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
|
static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
|
||||||
struct net_bridge *br = to->br;
|
|
||||||
if (unlikely(br->dev->priv_flags & IFF_IN_NETPOLL)) {
|
|
||||||
struct netpoll *np;
|
|
||||||
to->dev->npinfo = skb->dev->npinfo;
|
|
||||||
np = skb->dev->npinfo->netpoll;
|
|
||||||
np->real_dev = np->dev = to->dev;
|
|
||||||
to->dev->priv_flags |= IFF_IN_NETPOLL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
skb->dev = to->dev;
|
skb->dev = to->dev;
|
||||||
NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
|
NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
|
||||||
br_forward_finish);
|
br_forward_finish);
|
||||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
|
||||||
if (skb->dev->npinfo)
|
|
||||||
skb->dev->npinfo->netpoll->dev = br->dev;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
|
static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
|
||||||
|
Reference in New Issue
Block a user