Skip to content

Commit 72d2099

Browse files
larsksNipaLocal
authored andcommitted
ax25: Fix refcount imbalance on inbound connections
The first version of this patch was posted only to the linux-hams mailing list. It has been difficult to get the patch reviewed, but the patch has now been tested successfully by three people (that includes me) who have all verified that it prevents the crashes that were previously plaguing inbound ax.25 connections. Related discussions: - https://marc.info/?l=linux-hams&m=171629285223248&w=2 - https://marc.info/?l=linux-hams&m=171270115728031&w=2 >8------------------------------------------------------8< When releasing a socket in ax25_release(), we call netdev_put() to decrease the refcount on the associated ax.25 device. However, the execution path for accepting an incoming connection never calls netdev_hold(). This imbalance leads to refcount errors, and ultimately to kernel crashes. A typical call trace for the above situation looks like this: Call Trace: <TASK> ? show_regs+0x64/0x70 ? __warn+0x83/0x120 ? refcount_warn_saturate+0xb2/0x100 ? report_bug+0x158/0x190 ? prb_read_valid+0x20/0x30 ? handle_bug+0x3e/0x70 ? exc_invalid_op+0x1c/0x70 ? asm_exc_invalid_op+0x1f/0x30 ? refcount_warn_saturate+0xb2/0x100 ? refcount_warn_saturate+0xb2/0x100 ax25_release+0x2ad/0x360 __sock_release+0x35/0xa0 sock_close+0x19/0x20 [...] On reboot (or any attempt to remove the interface), the kernel gets stuck in an infinite loop: unregister_netdevice: waiting for ax0 to become free. Usage count = 0 This patch corrects these issues by ensuring that we call netdev_hold() and ax25_dev_hold() for new connections in ax25_accept(), balancing the calls to netdev_put() and ax25_dev_put() in ax25_release. Fixes: 7d8a3a4 Signed-off-by: Lars Kellogg-Stedman <[email protected]> Signed-off-by: NipaLocal <nipa@local>
1 parent 8f034bd commit 72d2099

File tree

1 file changed

+6
-0
lines changed

1 file changed

+6
-0
lines changed

net/ax25/af_ax25.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,6 +1381,8 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags,
13811381
DEFINE_WAIT(wait);
13821382
struct sock *sk;
13831383
int err = 0;
1384+
ax25_cb *ax25;
1385+
ax25_dev *ax25_dev;
13841386

13851387
if (sock->state != SS_UNCONNECTED)
13861388
return -EINVAL;
@@ -1434,6 +1436,10 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags,
14341436
kfree_skb(skb);
14351437
sk_acceptq_removed(sk);
14361438
newsock->state = SS_CONNECTED;
1439+
ax25 = sk_to_ax25(newsk);
1440+
ax25_dev = ax25->ax25_dev;
1441+
netdev_hold(ax25_dev->dev, &ax25->dev_tracker, GFP_ATOMIC);
1442+
ax25_dev_hold(ax25_dev);
14371443

14381444
out:
14391445
release_sock(sk);

0 commit comments

Comments
 (0)