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

Commit 0ce5964b authored by Herbert Xu's avatar Herbert Xu Committed by Greg Kroah-Hartman
Browse files

crypto: qat - Fix ADF_DEV_RESET_SYNC memory leak



commit d3b17c6d9dddc2db3670bc9be628b122416a3d26 upstream.

Using completion_done to determine whether the caller has gone
away only works after a complete call.  Furthermore it's still
possible that the caller has not yet called wait_for_completion,
resulting in another potential UAF.

Fix this by making the caller use cancel_work_sync and then freeing
the memory safely.

Fixes: 7d42e097607c ("crypto: qat - resolve race condition during AER recovery")
Cc: <stable@vger.kernel.org> #6.8+
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Reviewed-by: default avatarGiovanni Cabiddu <giovanni.cabiddu@intel.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 3c9ee829
Loading
Loading
Loading
Loading
+5 −14
Original line number Diff line number Diff line
@@ -139,8 +139,7 @@ static void adf_device_reset_worker(struct work_struct *work)
	if (adf_dev_init(accel_dev) || adf_dev_start(accel_dev)) {
		/* The device hanged and we can't restart it so stop here */
		dev_err(&GET_DEV(accel_dev), "Restart device failed\n");
		if (reset_data->mode == ADF_DEV_RESET_ASYNC ||
		    completion_done(&reset_data->compl))
		if (reset_data->mode == ADF_DEV_RESET_ASYNC)
			kfree(reset_data);
		WARN(1, "QAT: device restart failed. Device is unusable\n");
		return;
@@ -148,16 +147,8 @@ static void adf_device_reset_worker(struct work_struct *work)
	adf_dev_restarted_notify(accel_dev);
	clear_bit(ADF_STATUS_RESTARTING, &accel_dev->status);

	/*
	 * The dev is back alive. Notify the caller if in sync mode
	 *
	 * If device restart will take a more time than expected,
	 * the schedule_reset() function can timeout and exit. This can be
	 * detected by calling the completion_done() function. In this case
	 * the reset_data structure needs to be freed here.
	 */
	if (reset_data->mode == ADF_DEV_RESET_ASYNC ||
	    completion_done(&reset_data->compl))
	/* The dev is back alive. Notify the caller if in sync mode */
	if (reset_data->mode == ADF_DEV_RESET_ASYNC)
		kfree(reset_data);
	else
		complete(&reset_data->compl);
@@ -192,10 +183,10 @@ static int adf_dev_aer_schedule_reset(struct adf_accel_dev *accel_dev,
		if (!timeout) {
			dev_err(&GET_DEV(accel_dev),
				"Reset device timeout expired\n");
			cancel_work_sync(&reset_data->reset_work);
			ret = -EFAULT;
		} else {
			kfree(reset_data);
		}
		kfree(reset_data);
		return ret;
	}
	return 0;