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

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

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: default avatarPratham Pratap <prathampratap@codeaurora.org>
parent 120c562b
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -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);