[patch]fix race leading to a write after kfree in usbfs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

this fixes a race between async_completed() and proc_reapurbnonblock().
The patch should go into 2.6.31 but is not suitable for stable.

	Regards
		Oliver

Signed-off-by: Oliver Neukum <oliver@xxxxxxxxxx>

--

commit 041d773ad64ea12da9c7146763313ac15058cd1d
Author: Oliver Neukum <oliver@xxxxxxxxxx>
Date:   Wed Jul 8 19:01:18 2009 +0200

    usb:fix a race leading to a write after kfree in usbfs
    
    CPU A                   CPU B
    
    spin_lock(&ps->lock);
    list_move_tail(&as->asynclist, &ps->async_completed);
    spin_unlock(&ps->lock);
    
                                    if (!(as = async_getcompleted(ps)))
                                            return -EAGAIN;
                                    return processcompl(as, (void __user * __user *)arg);
    
    processcompl() calls free_async() which calls kfree(as)
    
    as->status = urb->status;
    if (as->signr) {
            sinfo.si_signo = as->signr;
            sinfo.si_errno = as->status;
            sinfo.si_code = SI_ASYNCIO;
            sinfo.si_addr = as->userurb;
            kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
                                  as->euid, as->secid);
    }
    snoop(&urb->dev->dev, "urb complete\n");
    snoop_urb(urb, as->userurb);
    
    write after kfree

diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 3086090..4160c04 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -325,21 +325,34 @@ static void async_completed(struct urb *urb)
 	struct async *as = urb->context;
 	struct dev_state *ps = as->ps;
 	struct siginfo sinfo;
+	struct pid *pid = NULL;
+	uid_t uid = 0;
+	uid_t euid = 0;
+	u32 secid = 0;
+	int signr;
 
 	spin_lock(&ps->lock);
 	list_move_tail(&as->asynclist, &ps->async_completed);
-	spin_unlock(&ps->lock);
 	as->status = urb->status;
-	if (as->signr) {
+	signr = as->signr;
+	if (signr) {
 		sinfo.si_signo = as->signr;
 		sinfo.si_errno = as->status;
 		sinfo.si_code = SI_ASYNCIO;
 		sinfo.si_addr = as->userurb;
-		kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
-				      as->euid, as->secid);
+		pid = as->pid;
+		uid = as->uid;
+		euid = as->euid;
+		secid = as->secid;
 	}
 	snoop(&urb->dev->dev, "urb complete\n");
 	snoop_urb(urb, as->userurb);
+	spin_unlock(&ps->lock);
+
+	if (signr)
+		kill_pid_info_as_uid(sinfo.si_signo, &sinfo, pid, uid,
+				      euid, secid);
+	
 	wake_up(&ps->wait);
 }
 

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux