usb: f_fs: Prevent race & use after free scenario on epfile

In case of fast composition switch along with disconnect/connect
performed, there are chances that the process of ep_disable,
function_disable, epfile_release & ep0_release race between each
other causing use after free scenarios.
This is seen with epfile struct itself and also with the read_buffer
member variable as well.

This change is a squash of below commits.

(1c3b63b8d818) usb: f_fs: Avoid use-after-free of epfile.
(971a85773340) usb: f_fs: Fix use-after-free for epfile.
(a008a43c5cd8) usb: f_fs: Prevent race between ep0_release & reset_work.
(f7fbba49e4a8) usb: f_fs: Fix Double free from ffs_data_clear.

Change-Id: If3f69e1e25be810aa82931b65fa2506b2e9f33bd
Signed-off-by: Pratham Pratap <prathampratap@codeaurora.org>
Signed-off-by: Udipto Goswami <quic_ugoswami@quicinc.com>
This commit is contained in:
Pratham Pratap
2021-02-02 14:42:56 +05:30
committed by Gerrit - the friendly Code Review server
parent a4341e9d9e
commit 5235024ca9

View File

@@ -1328,10 +1328,13 @@ ffs_epfile_release(struct inode *inode, struct file *file)
{
struct ffs_epfile *epfile = inode->i_private;
struct ffs_data *ffs = epfile->ffs;
unsigned long flags;
ENTER();
spin_lock_irqsave(&epfile->ffs->eps_lock, flags);
__ffs_epfile_read_buffer_free(epfile);
spin_unlock_irqrestore(&epfile->ffs->eps_lock, flags);
ffs_log("%s: state %d setup_state %d flag %lu opened %u",
epfile->name, epfile->ffs->state, epfile->ffs->setup_state,
epfile->ffs->flags, atomic_read(&epfile->opened));
@@ -1833,11 +1836,13 @@ static void ffs_data_closed(struct ffs_data *ffs)
if (atomic_dec_and_test(&ffs->opened)) {
if (ffs->no_disconnect) {
ffs->state = FFS_DEACTIVATED;
mutex_lock(&ffs->mutex);
if (ffs->epfiles) {
ffs_epfiles_destroy(ffs->epfiles,
ffs->eps_count);
ffs->epfiles = NULL;
}
mutex_unlock(&ffs->mutex);
if (ffs->setup_state == FFS_SETUP_PENDING)
__ffs_ep0_stall(ffs);
} else {
@@ -1909,15 +1914,22 @@ static void ffs_data_clear(struct ffs_data *ffs)
BUG_ON(ffs->gadget);
if (ffs->epfiles)
mutex_lock(&ffs->mutex);
if (ffs->epfiles) {
ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
ffs->epfiles = NULL;
}
if (ffs->ffs_eventfd)
eventfd_ctx_put(ffs->ffs_eventfd);
kfree(ffs->raw_descs_data);
ffs->raw_descs_data = NULL;
kfree(ffs->raw_strings);
ffs->raw_strings = NULL;
kfree(ffs->stringtabs);
ffs->stringtabs = NULL;
mutex_unlock(&ffs->mutex);
}
static void ffs_data_reset(struct ffs_data *ffs)
@@ -1929,11 +1941,7 @@ static void ffs_data_reset(struct ffs_data *ffs)
ffs_data_clear(ffs);
ffs->epfiles = NULL;
ffs->raw_descs_data = NULL;
ffs->raw_descs = NULL;
ffs->raw_strings = NULL;
ffs->stringtabs = NULL;
ffs->raw_descs_length = 0;
ffs->fs_descs_count = 0;
@@ -2073,16 +2081,19 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
static void ffs_func_eps_disable(struct ffs_function *func)
{
struct ffs_ep *ep = func->eps;
struct ffs_data *ffs = func->ffs;
struct ffs_epfile *epfile = func->ffs->epfiles;
unsigned count = func->ffs->eps_count;
struct ffs_ep *ep;
struct ffs_epfile *epfile;
unsigned short count;
unsigned long flags;
ffs_log("enter: state %d setup_state %d flag %lu", func->ffs->state,
func->ffs->setup_state, func->ffs->flags);
spin_lock_irqsave(&func->ffs->eps_lock, flags);
count = func->ffs->eps_count;
epfile = func->ffs->epfiles;
ep = func->eps;
while (count--) {
/* pending requests get nuked */
if (likely(ep->ep))