Commit df4a3e7f authored by Pi-Hsun Shih's avatar Pi-Hsun Shih Committed by Mauro Carvalho Chehab
Browse files

media: v4l2-ctrl: Lock main_hdl on operations of requests_queued.



There's a race condition between the list_del_init in the
v4l2_ctrl_request_complete, and the list_add_tail in the
v4l2_ctrl_request_queue, since they can be called in different thread
and the requests_queued list is not protected by a lock. This can lead
to that the v4l2_ctrl_handler is still in the requests_queued list while
the request_is_queued is already set to false, which would cause
use-after-free if the v4l2_ctrl_handler is later released.

Fix this by locking the ->lock of main_hdl (which is the owner of the
requests_queued list) when doing list operations on the
->requests_queued list.

Signed-off-by: default avatarPi-Hsun Shih <pihsun@chromium.org>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@kernel.org>
parent 2df200ab
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -3302,6 +3302,7 @@ static void v4l2_ctrl_request_queue(struct media_request_object *obj)
	struct v4l2_ctrl_handler *prev_hdl = NULL;
	struct v4l2_ctrl_ref *ref_ctrl, *ref_ctrl_prev = NULL;

	mutex_lock(main_hdl->lock);
	if (list_empty(&main_hdl->requests_queued))
		goto queue;

@@ -3333,18 +3334,22 @@ static void v4l2_ctrl_request_queue(struct media_request_object *obj)
queue:
	list_add_tail(&hdl->requests_queued, &main_hdl->requests_queued);
	hdl->request_is_queued = true;
	mutex_unlock(main_hdl->lock);
}

static void v4l2_ctrl_request_unbind(struct media_request_object *obj)
{
	struct v4l2_ctrl_handler *hdl =
		container_of(obj, struct v4l2_ctrl_handler, req_obj);
	struct v4l2_ctrl_handler *main_hdl = obj->priv;

	list_del_init(&hdl->requests);
	mutex_lock(main_hdl->lock);
	if (hdl->request_is_queued) {
		list_del_init(&hdl->requests_queued);
		hdl->request_is_queued = false;
	}
	mutex_unlock(main_hdl->lock);
}

static void v4l2_ctrl_request_release(struct media_request_object *obj)
@@ -4298,9 +4303,11 @@ void v4l2_ctrl_request_complete(struct media_request *req,
		v4l2_ctrl_unlock(ctrl);
	}

	mutex_lock(main_hdl->lock);
	WARN_ON(!hdl->request_is_queued);
	list_del_init(&hdl->requests_queued);
	hdl->request_is_queued = false;
	mutex_unlock(main_hdl->lock);
	media_request_object_complete(obj);
	media_request_object_put(obj);
}