Commit 516a1a07 authored by Oliver Neukum's avatar Oliver Neukum Committed by Greg Kroah-Hartman

USB: fix race leading to a write after kfree in usbfs

this fixes a race between async_completed() and proc_reapurbnonblock().

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
Signed-off-by: default avatarOliver Neukum <oliver@neukum.org>
parent 7bae0a07
...@@ -325,21 +325,34 @@ static void async_completed(struct urb *urb) ...@@ -325,21 +325,34 @@ static void async_completed(struct urb *urb)
struct async *as = urb->context; struct async *as = urb->context;
struct dev_state *ps = as->ps; struct dev_state *ps = as->ps;
struct siginfo sinfo; struct siginfo sinfo;
struct pid *pid = NULL;
uid_t uid = 0;
uid_t euid = 0;
u32 secid = 0;
int signr;
spin_lock(&ps->lock); spin_lock(&ps->lock);
list_move_tail(&as->asynclist, &ps->async_completed); list_move_tail(&as->asynclist, &ps->async_completed);
spin_unlock(&ps->lock);
as->status = urb->status; as->status = urb->status;
if (as->signr) { signr = as->signr;
if (signr) {
sinfo.si_signo = as->signr; sinfo.si_signo = as->signr;
sinfo.si_errno = as->status; sinfo.si_errno = as->status;
sinfo.si_code = SI_ASYNCIO; sinfo.si_code = SI_ASYNCIO;
sinfo.si_addr = as->userurb; sinfo.si_addr = as->userurb;
kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid, pid = as->pid;
as->euid, as->secid); uid = as->uid;
euid = as->euid;
secid = as->secid;
} }
snoop(&urb->dev->dev, "urb complete\n"); snoop(&urb->dev->dev, "urb complete\n");
snoop_urb(urb, as->userurb); 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); wake_up(&ps->wait);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment