Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5235024c authored by Pratham Pratap's avatar Pratham Pratap Committed by Gerrit - the friendly Code Review server
Browse files

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: default avatarPratham Pratap <prathampratap@codeaurora.org>
Signed-off-by: default avatarUdipto Goswami <quic_ugoswami@quicinc.com>
parent a4341e9d
Loading
Loading
Loading
Loading
+19 −8
Original line number Diff line number Diff line
@@ -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))