Thread (5 messages) 5 messages, 2 authors, 2022-03-15

Re: Re: Re: [PATCH V3] ax25: Fix refcount leaks caused by ax25_cb_del()

From: 周多明 <hidden>
Date: 2022-03-15 01:15:10
Also in: linux-hams, lkml
Subsystem: networking [general], the rest · Maintainers: "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds

Hello,

On Mon, 14 Mar 2022 14:02:56 +0300, Dan Carpen wrote:
quoted
quoted
But even here, my instinct is that if the refcounting is were done in
the correct place we would not need any additional variables.  Is there
no simpler solution?
I think there is a simpler solution instead of using any additional variables,
which is shown below:
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index 6bd09718077..0886109421a 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -98,8 +98,10 @@ static void ax25_kill_by_device(struct net_device *dev)
 			spin_unlock_bh(&ax25_list_lock);
 			lock_sock(sk);
 			s->ax25_dev = NULL;
-			dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker);
-			ax25_dev_put(ax25_dev);
+			if (sk->sk_wq) {
+				dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker);
+				ax25_dev_put(ax25_dev);
+			}
 			ax25_disconnect(s, ENETUNREACH);
 			release_sock(sk);
 			spin_lock_bh(&ax25_list_lock);
@@ -979,14 +981,20 @@ static int ax25_release(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
 	ax25_cb *ax25;
+	ax25_dev *ax25_dev;
 
 	if (sk == NULL)
 		return 0;
 
 	sock_hold(sk);
-	sock_orphan(sk);
 	lock_sock(sk);
+	sock_orphan(sk);
 	ax25 = sk_to_ax25(sk);
+	ax25_dev = ax25->ax25_dev;
+	if (ax25_dev) {
+		dev_put_track(ax25_dev->dev, &ax25_dev->dev_tracker);
+		ax25_dev_put(ax25_dev);
+	}
 
 	if (sk->sk_type == SOCK_SEQPACKET) {
 		switch (ax25->state) {
we add decrements of refcounts in ax25_release(), and use lock_sock() to do synchronization. 
If refcounts decrease in ax25_release(), the decrements of refcounts in ax25_kill_by_device() 
will not be executed and vice versa. 

1. If we decrease the refcounts in ax25_release(), the decrements of refcounts in 
ax25_kill_by_device() will not execute. Because we set NULL to sk->sk_wq in sock_orphan()
and we check whether sk->sk_wq is NULL in ax25_kill_by_device(). Only positions (3) and (4)
could execute.

     (Thread 1)                      |      
ax25_bind()                          |
 ...                                 |
 ax25_addr_ax25dev()                 |
  ax25_dev_hold()   //(1)            |
  ...                                |
 dev_hold_track()   //(2)            |     (Thread 2)
 ...                                 | ax25_release()
                                     |  ...
                                     |   lock_sock(sk)
                                     |   sock_orphan(sk)
                                     |     sk->sk_wq  = NULL //set NULL
                                     |   ...
                                     |   if (ax25_dev) {
                                     |    dev_put_track() //(3)
                                     |    ax25_dev_put() //(4)
                                     |
     (thread 3)                      |
ax25_kill_by_device()                |
 ...                                 |
 lock_sock(sk)                       |
 s->ax25_dev = NULL                  |
 if (sk->sk_wq) { //check            |
  dev_put_track() //(5)              |
  ax25_dev_put() //(6)               |


2. If we decrease refcounts in ax25_kill_by_device(), the decrements of refcounts 
in ax25_release() will not execute. Because we set NULL to s->ax25_dev in ax25_kill_by_device()
and we check whether ax25_dev is NULL in ax25_release(). Only positions (3) and (4)
could execute.

     (Thread 1)                      | 
ax25_bind()                          |
 ...                                 |
 ax25_addr_ax25dev()                 |
  ax25_dev_hold()   //(1)            |
  ...                                |
 dev_hold_track()   //(2)            |      (Thread 2)
 ...                                 | ax25_kill_by_device()
                                     |  ...
                                     |   lock_sock(sk)
                                     |   s->ax25_dev = NULL //set NULL
                                     |   if (sk->sk_wq) {
                                     |    dev_put_track() //(3)
                                     |    ax25_dev_put() //(4)
                                     |    ...
                                     |
     (thread 3)                      |
ax25_release()                       |
 ...                                 |
 lock_sock(sk);                      |
 sock_orphan(sk);                    |
 ...                                 |
 if (ax25_dev) { //check             |
  dev_put_track() //(5)              |
  ax25_dev_put() //(6)               |
quoted
I sent "[PATCH net V2 1/2] ax25: Fix refcount leaks caused by ax25_cb_del()"
on On Fri, Mar 11, 2022. Could this patch solve your question?
I had a bunch of questions...  You just ignored them, and sent a patch
called v2 instead of v4 so I was puzzled and confused. I guess the
answer is no, could you please answer the questions?
I hope my answer could solve your questions. If you still have any questions
welcome to send email to me. I will send "[PATCH net V4 1/2] ax25: Fix
refcount leaks caused by ax25_cb_del()" as soon as possible. 

What`s more, I found NPD bugs in ax25 timers, I will send
"[PATCH net V4 2/2] ax25: Fix NULL pointer dereferences in ax25 timers" together.

Best wishes,
Duoming Zhou
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help