From: Ralf Lici ovpn injects decrypted packets into the netdev RX path through ovpn_netdev_write() -> gro_cells_receive(). In case of TCP connections, that injection path can be reached from either softirq or process context. However, gro_cells_receive() expects to be invoked in softirq context to avoid racing its lock acquisition. When being invoked from process context, we must ensure BH are disabled to safeguard gro_cells_receive() assumption. As of now this is not the case and the following WARNING is triggered: [ 230.183747][ T12] WARNING: net/core/gro_cells.c:30 at gro_cells_receive+0x708/0xaa0, CPU#1: kworker/u16:0/12 Moreover, not disabling BH was also triggering lockdep, which was reporting a potential deadlock in case of concurrent softirq and process context gro_cells->bh_lock acquisition (i.e in case of concurrent UDP and TCP connection for the same ovpn interface): WARNING: inconsistent lock state 7.0.0-rc4+ #246 Tainted: G W -------------------------------- inconsistent {IN-SOFTIRQ-W} -> {SOFTIRQ-ON-W} usage. Fix all this by invoking local_bh_disable/enable() around gro_cells_receive(). Fixes: 11851cbd60ea ("ovpn: implement TCP transport") Signed-off-by: Ralf Lici Signed-off-by: Antonio Quartulli --- drivers/net/ovpn/io.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c index d92bb87be2b2..c0fdb9504241 100644 --- a/drivers/net/ovpn/io.c +++ b/drivers/net/ovpn/io.c @@ -91,7 +91,13 @@ static void ovpn_netdev_write(struct ovpn_peer *peer, struct sk_buff *skb) /* cause packet to be "received" by the interface */ pkt_len = skb->len; + /* we may get here in process context in case of TCP connections, + * therefore we have to disable BHs to ensure gro_cells_receive() + * doesn't enter deadlock + */ + local_bh_disable(); ret = gro_cells_receive(&peer->ovpn->gro_cells, skb); + local_bh_enable(); if (likely(ret == NET_RX_SUCCESS)) { /* update RX stats with the size of decrypted packet */ ovpn_peer_stats_increment_rx(&peer->vpn_stats, pkt_len); -- 2.53.0