This is a note to let you know that I've just added the patch titled

    sunrpc: prevent use-after-free on clearing XPT_BUSY

to the 2.6.32-longterm tree which can be found at:
    
http://www.kernel.org/git/?p=linux/kernel/git/longterm/longterm-queue-2.6.32.git;a=summary

The filename of the patch is:
     sunrpc-prevent-use-after-free-on-clearing-xpt_busy.patch
and it can be found in the queue-2.6.32 subdirectory.

If you, or anyone else, feels it should not be added to the 2.6.32 longterm 
tree,
please let <[email protected]> know about it.


>From ed2849d3ecfa339435818eeff28f6c3424300cec Mon Sep 17 00:00:00 2001
From: NeilBrown <[email protected]>
Date: Tue, 16 Nov 2010 16:55:19 +1100
Subject: sunrpc: prevent use-after-free on clearing XPT_BUSY

From: NeilBrown <[email protected]>

commit ed2849d3ecfa339435818eeff28f6c3424300cec upstream.

When an xprt is created, it has a refcount of 1, and XPT_BUSY is set.
The refcount is *not* owned by the thread that created the xprt
(as is clear from the fact that creators never put the reference).
Rather, it is owned by the absence of XPT_DEAD.  Once XPT_DEAD is set,
(And XPT_BUSY is clear) that initial reference is dropped and the xprt
can be freed.

So when a creator clears XPT_BUSY it is dropping its only reference and
so must not touch the xprt again.

However svc_recv, after calling ->xpo_accept (and so getting an XPT_BUSY
reference on a new xprt), calls svc_xprt_recieved.  This clears
XPT_BUSY and then svc_xprt_enqueue - this last without owning a reference.
This is dangerous and has been seen to leave svc_xprt_enqueue working
with an xprt containing garbage.

So we need to hold an extra counted reference over that call to
svc_xprt_received.

For safety, any time we clear XPT_BUSY and then use the xprt again, we
first get a reference, and the put it again afterwards.

Note that svc_close_all does not need this extra protection as there are
no threads running, and the final free can only be called asynchronously
from such a thread.

Signed-off-by: NeilBrown <[email protected]>
Signed-off-by: J. Bruce Fields <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

---
 net/sunrpc/svc_xprt.c |    9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -209,6 +209,7 @@ int svc_create_xprt(struct svc_serv *ser
        spin_lock(&svc_xprt_class_lock);
        list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) {
                struct svc_xprt *newxprt;
+               unsigned short newport;
 
                if (strcmp(xprt_name, xcl->xcl_name))
                        continue;
@@ -227,8 +228,9 @@ int svc_create_xprt(struct svc_serv *ser
                spin_lock_bh(&serv->sv_lock);
                list_add(&newxprt->xpt_list, &serv->sv_permsocks);
                spin_unlock_bh(&serv->sv_lock);
+               newport = svc_xprt_local_port(newxprt);
                clear_bit(XPT_BUSY, &newxprt->xpt_flags);
-               return svc_xprt_local_port(newxprt);
+               return newport;
        }
  err:
        spin_unlock(&svc_xprt_class_lock);
@@ -430,8 +432,13 @@ void svc_xprt_received(struct svc_xprt *
 {
        BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags));
        xprt->xpt_pool = NULL;
+       /* As soon as we clear busy, the xprt could be closed and
+        * 'put', so we need a reference to call svc_xprt_enqueue with:
+        */
+       svc_xprt_get(xprt);
        clear_bit(XPT_BUSY, &xprt->xpt_flags);
        svc_xprt_enqueue(xprt);
+       svc_xprt_put(xprt);
 }
 EXPORT_SYMBOL_GPL(svc_xprt_received);
 


Patches currently in longterm-queue-2.6.32 which might be from [email protected] are

_______________________________________________
stable mailing list
[email protected]
http://linux.kernel.org/mailman/listinfo/stable

Reply via email to