usb: f_fs: Avoid use-after-free of ffs_data

Consider a case, where ffs_func_unbind was called twice due to some
reason and the opts->refcnt becomes NULL causing functionfs_unbind
to happen. This will free the ffs_data structure but later in the
function it is being used to add ffs_event which can lead to UAF
scenario. Avoid this by returning early from ffs_func_unbind function.
While we are at it, let's say ffs_epfile_io (which will be called from
ffs_epfile_read_iter) is called after functionfs_unbind happened then
there is a possibility the driver may end up using already freed
ffs_data. Fix it by initializing the variable after the FFS_ACTIVE
check.

Change-Id: Ic04857f95a6756d2d177bfbc382a11ffd651ef62
Signed-off-by: Pratham Pratap <prathampratap@codeaurora.org>
This commit is contained in:
Pratham Pratap 2021-04-02 15:49:30 +05:30 committed by Gerrit - the friendly Code Review server
parent 120c562bdf
commit 2df1806a2b

View file

@ -940,7 +940,7 @@ static ssize_t __ffs_epfile_read_data(struct ffs_epfile *epfile,
static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
{
struct ffs_epfile *epfile = file->private_data;
struct ffs_data *ffs = epfile->ffs;
struct ffs_data *ffs;
struct usb_request *req;
struct ffs_ep *ep;
char *data = NULL;
@ -948,12 +948,13 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
int halt;
size_t extra_buf_alloc = 0;
ffs_log("enter: %s", epfile->name);
/* Are we still active? */
if (WARN_ON(epfile->ffs->state != FFS_ACTIVE))
return -ENODEV;
ffs = epfile->ffs;
ffs_log("enter: %s", epfile->name);
/* Wait for endpoint to be enabled */
ep = epfile->ep;
if (!ep) {
@ -3775,8 +3776,11 @@ static void ffs_func_unbind(struct usb_configuration *c,
ffs->func = NULL;
}
if (!--opts->refcnt)
if (!--opts->refcnt) {
ffs_event_add(ffs, FUNCTIONFS_UNBIND);
functionfs_unbind(ffs);
return;
}
/* cleanup after autoconfig */
spin_lock_irqsave(&func->ffs->eps_lock, flags);