VYPR
High severity7.8NVD Advisory· Published Apr 24, 2026· Updated Apr 27, 2026

CVE-2026-31667

CVE-2026-31667

Description

A circular locking dependency in Linux kernel's uinput driver allows local denial-of-service when using force-feedback controllers via ff-core, fixed by introducing a spinlock to break the lock chain.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

A circular locking dependency in Linux kernel's uinput driver allows local denial-of-service when using force-feedback controllers via ff-core, fixed by introducing a spinlock to break the lock chain.

Vulnerability

A circular locking dependency (lockdep) exists in the Linux kernel's uinput driver when force-feedback (ff) effects are uploaded through the ff-core subsystem. The cycle involves four mutex acqusition paths: 1) ff->mutexudev->mutex (ff upload), 2) udev->mutexinput_mutex (device create), 3) input_mutexdev->mutex (device register), and 4) dev->mutexff->mutex (evdev release). The bug is triggered in user-accessible scenarios such as using a force-feedback gamepad with uinput (e.g., playing ELDEN RING under Wine with a Flydigi Vader 5 controller). Affected versions include all Linux kernel releases that have the uinput driver with force-feedback support and the described locking paths; the fix has been backported to stable trees via commits [1], [2], [3], and [4].

Exploitation

An attacker requires local user access and the ability to interact with a uinput device that supports force-feedback. Specifically, the attack involves uploading a force-feedback effect via input_ff_upload(), which triggers the circular lock chain. The sequence does not require root privileges if the user has permission to open and write to /dev/uinput and the system has a force-feedback device attached. No race window or special timing is needed; the lockdep deadlock can be reproduced consistently by simply playing a game that uses force-feedback with uinput.

Impact

A successful exploitation leads to a kernel deadlock (denial-of-service) due to the circular mutex dependency, rendering the system unresponsive or causing a kernel hang. An attacker cannot achieve arbitrary code execution or privilege escalation directly from this vulnerability — the impact is limited to local denial-of-service, as the locking stall prevents further progress of affected processes and may require a system reboot.

Mitigation

The fix is implemented in Linux kernel commits [1], [2], [3], and [4] (stable tree backports). The resolution introduces a new state_lock spinlock to protect udev->state and udev->dev access in uinput_request_send() instead of acquiring udev->mutex. Breaking the ff->mutex → udev->mutex link since a spinlock is a leaf in lock ordering and cannot form cycles with mutexes. Additionally, init_completion(&request->done) is moved from uinput_request_send() to uinput_request_submit(). Users should update to a kernel version containing these patches. If patching is not immediately possible, disabling force-feedback for uinput devices or restricting local user access to /dev/uinput may mitigate the risk, though no full workaround is provided.

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

10
  • Linux/Kernel10 versions
    cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*+ 9 more
    • cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*range: >=2.6.19.1,<5.10.253
    • cpe:2.3:o:linux:linux_kernel:2.6.19:-:*:*:*:*:*:*
    • cpe:2.3:o:linux:linux_kernel:7.0:rc1:*:*:*:*:*:*
    • cpe:2.3:o:linux:linux_kernel:7.0:rc2:*:*:*:*:*:*
    • cpe:2.3:o:linux:linux_kernel:7.0:rc3:*:*:*:*:*:*
    • cpe:2.3:o:linux:linux_kernel:7.0:rc4:*:*:*:*:*:*
    • cpe:2.3:o:linux:linux_kernel:7.0:rc5:*:*:*:*:*:*
    • cpe:2.3:o:linux:linux_kernel:7.0:rc6:*:*:*:*:*:*
    • cpe:2.3:o:linux:linux_kernel:7.0:rc7:*:*:*:*:*:*
    • (no CPE)

Patches

16
4cda78d6f8bf

Input: uinput - fix circular locking dependency with ff-core

1 file changed · +21 8
  • drivers/input/misc/uinput.c+21 8 modified
    diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
    index 13336a2fd49c8..a973e82205b5c 100644
    --- a/drivers/input/misc/uinput.c
    +++ b/drivers/input/misc/uinput.c
    @@ -57,6 +57,7 @@ struct uinput_device {
     	struct input_dev	*dev;
     	struct mutex		mutex;
     	enum uinput_state	state;
    +	spinlock_t		state_lock;
     	wait_queue_head_t	waitq;
     	unsigned char		ready;
     	unsigned char		head;
    @@ -146,19 +147,15 @@ static void uinput_request_release_slot(struct uinput_device *udev,
     static int uinput_request_send(struct uinput_device *udev,
     			       struct uinput_request *request)
     {
    -	int retval;
    +	int retval = 0;
     
    -	retval = mutex_lock_interruptible(&udev->mutex);
    -	if (retval)
    -		return retval;
    +	spin_lock(&udev->state_lock);
     
     	if (udev->state != UIST_CREATED) {
     		retval = -ENODEV;
     		goto out;
     	}
     
    -	init_completion(&request->done);
    -
     	/*
     	 * Tell our userspace application about this new request
     	 * by queueing an input event.
    @@ -166,7 +163,7 @@ static int uinput_request_send(struct uinput_device *udev,
     	uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
     
      out:
    -	mutex_unlock(&udev->mutex);
    +	spin_unlock(&udev->state_lock);
     	return retval;
     }
     
    @@ -175,6 +172,13 @@ static int uinput_request_submit(struct uinput_device *udev,
     {
     	int retval;
     
    +	/*
    +	 * Initialize completion before allocating the request slot.
    +	 * Once the slot is allocated, uinput_flush_requests() may
    +	 * complete it at any time, so it must be initialized first.
    +	 */
    +	init_completion(&request->done);
    +
     	retval = uinput_request_reserve_slot(udev, request);
     	if (retval)
     		return retval;
    @@ -289,7 +293,14 @@ static void uinput_destroy_device(struct uinput_device *udev)
     	struct input_dev *dev = udev->dev;
     	enum uinput_state old_state = udev->state;
     
    +	/*
    +	 * Update state under state_lock so that concurrent
    +	 * uinput_request_send() sees the state change before we
    +	 * flush pending requests and tear down the device.
    +	 */
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_NEW_DEVICE;
    +	spin_unlock(&udev->state_lock);
     
     	if (dev) {
     		name = dev->name;
    @@ -366,7 +377,9 @@ static int uinput_create_device(struct uinput_device *udev)
     	if (error)
     		goto fail2;
     
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_CREATED;
    +	spin_unlock(&udev->state_lock);
     
     	return 0;
     
    @@ -384,6 +397,7 @@ static int uinput_open(struct inode *inode, struct file *file)
     		return -ENOMEM;
     
     	mutex_init(&newdev->mutex);
    +	spin_lock_init(&newdev->state_lock);
     	spin_lock_init(&newdev->requests_lock);
     	init_waitqueue_head(&newdev->requests_waitq);
     	init_waitqueue_head(&newdev->waitq);
    -- 
    cgit 1.3-korg
    
    
    
1534661043c4

Input: uinput - fix circular locking dependency with ff-core

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitMikhail GavrilovFixed in 6.19.13via kernel-cna
1 file changed · +21 8
  • drivers/input/misc/uinput.c+21 8 modified
    diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
    index 13336a2fd49c8..a973e82205b5c 100644
    --- a/drivers/input/misc/uinput.c
    +++ b/drivers/input/misc/uinput.c
    @@ -57,6 +57,7 @@ struct uinput_device {
     	struct input_dev	*dev;
     	struct mutex		mutex;
     	enum uinput_state	state;
    +	spinlock_t		state_lock;
     	wait_queue_head_t	waitq;
     	unsigned char		ready;
     	unsigned char		head;
    @@ -146,19 +147,15 @@ static void uinput_request_release_slot(struct uinput_device *udev,
     static int uinput_request_send(struct uinput_device *udev,
     			       struct uinput_request *request)
     {
    -	int retval;
    +	int retval = 0;
     
    -	retval = mutex_lock_interruptible(&udev->mutex);
    -	if (retval)
    -		return retval;
    +	spin_lock(&udev->state_lock);
     
     	if (udev->state != UIST_CREATED) {
     		retval = -ENODEV;
     		goto out;
     	}
     
    -	init_completion(&request->done);
    -
     	/*
     	 * Tell our userspace application about this new request
     	 * by queueing an input event.
    @@ -166,7 +163,7 @@ static int uinput_request_send(struct uinput_device *udev,
     	uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
     
      out:
    -	mutex_unlock(&udev->mutex);
    +	spin_unlock(&udev->state_lock);
     	return retval;
     }
     
    @@ -175,6 +172,13 @@ static int uinput_request_submit(struct uinput_device *udev,
     {
     	int retval;
     
    +	/*
    +	 * Initialize completion before allocating the request slot.
    +	 * Once the slot is allocated, uinput_flush_requests() may
    +	 * complete it at any time, so it must be initialized first.
    +	 */
    +	init_completion(&request->done);
    +
     	retval = uinput_request_reserve_slot(udev, request);
     	if (retval)
     		return retval;
    @@ -289,7 +293,14 @@ static void uinput_destroy_device(struct uinput_device *udev)
     	struct input_dev *dev = udev->dev;
     	enum uinput_state old_state = udev->state;
     
    +	/*
    +	 * Update state under state_lock so that concurrent
    +	 * uinput_request_send() sees the state change before we
    +	 * flush pending requests and tear down the device.
    +	 */
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_NEW_DEVICE;
    +	spin_unlock(&udev->state_lock);
     
     	if (dev) {
     		name = dev->name;
    @@ -366,7 +377,9 @@ static int uinput_create_device(struct uinput_device *udev)
     	if (error)
     		goto fail2;
     
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_CREATED;
    +	spin_unlock(&udev->state_lock);
     
     	return 0;
     
    @@ -384,6 +397,7 @@ static int uinput_open(struct inode *inode, struct file *file)
     		return -ENOMEM;
     
     	mutex_init(&newdev->mutex);
    +	spin_lock_init(&newdev->state_lock);
     	spin_lock_init(&newdev->requests_lock);
     	init_waitqueue_head(&newdev->requests_waitq);
     	init_waitqueue_head(&newdev->waitq);
    -- 
    cgit 1.3-korg
    
    
    
1e09dfbb4f5d

Input: uinput - fix circular locking dependency with ff-core

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitMikhail GavrilovFixed in 6.18.23via kernel-cna
1 file changed · +21 8
  • drivers/input/misc/uinput.c+21 8 modified
    diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
    index 13336a2fd49c8..a973e82205b5c 100644
    --- a/drivers/input/misc/uinput.c
    +++ b/drivers/input/misc/uinput.c
    @@ -57,6 +57,7 @@ struct uinput_device {
     	struct input_dev	*dev;
     	struct mutex		mutex;
     	enum uinput_state	state;
    +	spinlock_t		state_lock;
     	wait_queue_head_t	waitq;
     	unsigned char		ready;
     	unsigned char		head;
    @@ -146,19 +147,15 @@ static void uinput_request_release_slot(struct uinput_device *udev,
     static int uinput_request_send(struct uinput_device *udev,
     			       struct uinput_request *request)
     {
    -	int retval;
    +	int retval = 0;
     
    -	retval = mutex_lock_interruptible(&udev->mutex);
    -	if (retval)
    -		return retval;
    +	spin_lock(&udev->state_lock);
     
     	if (udev->state != UIST_CREATED) {
     		retval = -ENODEV;
     		goto out;
     	}
     
    -	init_completion(&request->done);
    -
     	/*
     	 * Tell our userspace application about this new request
     	 * by queueing an input event.
    @@ -166,7 +163,7 @@ static int uinput_request_send(struct uinput_device *udev,
     	uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
     
      out:
    -	mutex_unlock(&udev->mutex);
    +	spin_unlock(&udev->state_lock);
     	return retval;
     }
     
    @@ -175,6 +172,13 @@ static int uinput_request_submit(struct uinput_device *udev,
     {
     	int retval;
     
    +	/*
    +	 * Initialize completion before allocating the request slot.
    +	 * Once the slot is allocated, uinput_flush_requests() may
    +	 * complete it at any time, so it must be initialized first.
    +	 */
    +	init_completion(&request->done);
    +
     	retval = uinput_request_reserve_slot(udev, request);
     	if (retval)
     		return retval;
    @@ -289,7 +293,14 @@ static void uinput_destroy_device(struct uinput_device *udev)
     	struct input_dev *dev = udev->dev;
     	enum uinput_state old_state = udev->state;
     
    +	/*
    +	 * Update state under state_lock so that concurrent
    +	 * uinput_request_send() sees the state change before we
    +	 * flush pending requests and tear down the device.
    +	 */
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_NEW_DEVICE;
    +	spin_unlock(&udev->state_lock);
     
     	if (dev) {
     		name = dev->name;
    @@ -366,7 +377,9 @@ static int uinput_create_device(struct uinput_device *udev)
     	if (error)
     		goto fail2;
     
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_CREATED;
    +	spin_unlock(&udev->state_lock);
     
     	return 0;
     
    @@ -384,6 +397,7 @@ static int uinput_open(struct inode *inode, struct file *file)
     		return -ENOMEM;
     
     	mutex_init(&newdev->mutex);
    +	spin_lock_init(&newdev->state_lock);
     	spin_lock_init(&newdev->requests_lock);
     	init_waitqueue_head(&newdev->requests_waitq);
     	init_waitqueue_head(&newdev->waitq);
    -- 
    cgit 1.3-korg
    
    
    
a3d6c9c053c9

Input: uinput - fix circular locking dependency with ff-core

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitMikhail GavrilovFixed in 6.12.82via kernel-cna
1 file changed · +21 8
  • drivers/input/misc/uinput.c+21 8 modified
    diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
    index 13336a2fd49c8..a973e82205b5c 100644
    --- a/drivers/input/misc/uinput.c
    +++ b/drivers/input/misc/uinput.c
    @@ -57,6 +57,7 @@ struct uinput_device {
     	struct input_dev	*dev;
     	struct mutex		mutex;
     	enum uinput_state	state;
    +	spinlock_t		state_lock;
     	wait_queue_head_t	waitq;
     	unsigned char		ready;
     	unsigned char		head;
    @@ -146,19 +147,15 @@ static void uinput_request_release_slot(struct uinput_device *udev,
     static int uinput_request_send(struct uinput_device *udev,
     			       struct uinput_request *request)
     {
    -	int retval;
    +	int retval = 0;
     
    -	retval = mutex_lock_interruptible(&udev->mutex);
    -	if (retval)
    -		return retval;
    +	spin_lock(&udev->state_lock);
     
     	if (udev->state != UIST_CREATED) {
     		retval = -ENODEV;
     		goto out;
     	}
     
    -	init_completion(&request->done);
    -
     	/*
     	 * Tell our userspace application about this new request
     	 * by queueing an input event.
    @@ -166,7 +163,7 @@ static int uinput_request_send(struct uinput_device *udev,
     	uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
     
      out:
    -	mutex_unlock(&udev->mutex);
    +	spin_unlock(&udev->state_lock);
     	return retval;
     }
     
    @@ -175,6 +172,13 @@ static int uinput_request_submit(struct uinput_device *udev,
     {
     	int retval;
     
    +	/*
    +	 * Initialize completion before allocating the request slot.
    +	 * Once the slot is allocated, uinput_flush_requests() may
    +	 * complete it at any time, so it must be initialized first.
    +	 */
    +	init_completion(&request->done);
    +
     	retval = uinput_request_reserve_slot(udev, request);
     	if (retval)
     		return retval;
    @@ -289,7 +293,14 @@ static void uinput_destroy_device(struct uinput_device *udev)
     	struct input_dev *dev = udev->dev;
     	enum uinput_state old_state = udev->state;
     
    +	/*
    +	 * Update state under state_lock so that concurrent
    +	 * uinput_request_send() sees the state change before we
    +	 * flush pending requests and tear down the device.
    +	 */
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_NEW_DEVICE;
    +	spin_unlock(&udev->state_lock);
     
     	if (dev) {
     		name = dev->name;
    @@ -366,7 +377,9 @@ static int uinput_create_device(struct uinput_device *udev)
     	if (error)
     		goto fail2;
     
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_CREATED;
    +	spin_unlock(&udev->state_lock);
     
     	return 0;
     
    @@ -384,6 +397,7 @@ static int uinput_open(struct inode *inode, struct file *file)
     		return -ENOMEM;
     
     	mutex_init(&newdev->mutex);
    +	spin_lock_init(&newdev->state_lock);
     	spin_lock_init(&newdev->requests_lock);
     	init_waitqueue_head(&newdev->requests_waitq);
     	init_waitqueue_head(&newdev->waitq);
    -- 
    cgit 1.3-korg
    
    
    
546c18a14924

Input: uinput - fix circular locking dependency with ff-core

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitMikhail GavrilovFixed in 6.6.135via kernel-cna
1 file changed · +21 8
  • drivers/input/misc/uinput.c+21 8 modified
    diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
    index edb62a284548b..fd624c35a328f 100644
    --- a/drivers/input/misc/uinput.c
    +++ b/drivers/input/misc/uinput.c
    @@ -57,6 +57,7 @@ struct uinput_device {
     	struct input_dev	*dev;
     	struct mutex		mutex;
     	enum uinput_state	state;
    +	spinlock_t		state_lock;
     	wait_queue_head_t	waitq;
     	unsigned char		ready;
     	unsigned char		head;
    @@ -146,19 +147,15 @@ static void uinput_request_release_slot(struct uinput_device *udev,
     static int uinput_request_send(struct uinput_device *udev,
     			       struct uinput_request *request)
     {
    -	int retval;
    +	int retval = 0;
     
    -	retval = mutex_lock_interruptible(&udev->mutex);
    -	if (retval)
    -		return retval;
    +	spin_lock(&udev->state_lock);
     
     	if (udev->state != UIST_CREATED) {
     		retval = -ENODEV;
     		goto out;
     	}
     
    -	init_completion(&request->done);
    -
     	/*
     	 * Tell our userspace application about this new request
     	 * by queueing an input event.
    @@ -166,7 +163,7 @@ static int uinput_request_send(struct uinput_device *udev,
     	uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
     
      out:
    -	mutex_unlock(&udev->mutex);
    +	spin_unlock(&udev->state_lock);
     	return retval;
     }
     
    @@ -175,6 +172,13 @@ static int uinput_request_submit(struct uinput_device *udev,
     {
     	int retval;
     
    +	/*
    +	 * Initialize completion before allocating the request slot.
    +	 * Once the slot is allocated, uinput_flush_requests() may
    +	 * complete it at any time, so it must be initialized first.
    +	 */
    +	init_completion(&request->done);
    +
     	retval = uinput_request_reserve_slot(udev, request);
     	if (retval)
     		return retval;
    @@ -289,7 +293,14 @@ static void uinput_destroy_device(struct uinput_device *udev)
     	struct input_dev *dev = udev->dev;
     	enum uinput_state old_state = udev->state;
     
    +	/*
    +	 * Update state under state_lock so that concurrent
    +	 * uinput_request_send() sees the state change before we
    +	 * flush pending requests and tear down the device.
    +	 */
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_NEW_DEVICE;
    +	spin_unlock(&udev->state_lock);
     
     	if (dev) {
     		name = dev->name;
    @@ -366,7 +377,9 @@ static int uinput_create_device(struct uinput_device *udev)
     	if (error)
     		goto fail2;
     
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_CREATED;
    +	spin_unlock(&udev->state_lock);
     
     	return 0;
     
    @@ -384,6 +397,7 @@ static int uinput_open(struct inode *inode, struct file *file)
     		return -ENOMEM;
     
     	mutex_init(&newdev->mutex);
    +	spin_lock_init(&newdev->state_lock);
     	spin_lock_init(&newdev->requests_lock);
     	init_waitqueue_head(&newdev->requests_waitq);
     	init_waitqueue_head(&newdev->waitq);
    -- 
    cgit 1.3-korg
    
    
    
974f7b138c3a

Input: uinput - fix circular locking dependency with ff-core

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitMikhail GavrilovFixed in 6.1.169via kernel-cna
1 file changed · +21 8
  • drivers/input/misc/uinput.c+21 8 modified
    diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
    index faed4590a8a92..bd8be236af756 100644
    --- a/drivers/input/misc/uinput.c
    +++ b/drivers/input/misc/uinput.c
    @@ -56,6 +56,7 @@ struct uinput_device {
     	struct input_dev	*dev;
     	struct mutex		mutex;
     	enum uinput_state	state;
    +	spinlock_t		state_lock;
     	wait_queue_head_t	waitq;
     	unsigned char		ready;
     	unsigned char		head;
    @@ -145,19 +146,15 @@ static void uinput_request_release_slot(struct uinput_device *udev,
     static int uinput_request_send(struct uinput_device *udev,
     			       struct uinput_request *request)
     {
    -	int retval;
    +	int retval = 0;
     
    -	retval = mutex_lock_interruptible(&udev->mutex);
    -	if (retval)
    -		return retval;
    +	spin_lock(&udev->state_lock);
     
     	if (udev->state != UIST_CREATED) {
     		retval = -ENODEV;
     		goto out;
     	}
     
    -	init_completion(&request->done);
    -
     	/*
     	 * Tell our userspace application about this new request
     	 * by queueing an input event.
    @@ -165,7 +162,7 @@ static int uinput_request_send(struct uinput_device *udev,
     	uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
     
      out:
    -	mutex_unlock(&udev->mutex);
    +	spin_unlock(&udev->state_lock);
     	return retval;
     }
     
    @@ -174,6 +171,13 @@ static int uinput_request_submit(struct uinput_device *udev,
     {
     	int retval;
     
    +	/*
    +	 * Initialize completion before allocating the request slot.
    +	 * Once the slot is allocated, uinput_flush_requests() may
    +	 * complete it at any time, so it must be initialized first.
    +	 */
    +	init_completion(&request->done);
    +
     	retval = uinput_request_reserve_slot(udev, request);
     	if (retval)
     		return retval;
    @@ -288,7 +292,14 @@ static void uinput_destroy_device(struct uinput_device *udev)
     	struct input_dev *dev = udev->dev;
     	enum uinput_state old_state = udev->state;
     
    +	/*
    +	 * Update state under state_lock so that concurrent
    +	 * uinput_request_send() sees the state change before we
    +	 * flush pending requests and tear down the device.
    +	 */
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_NEW_DEVICE;
    +	spin_unlock(&udev->state_lock);
     
     	if (dev) {
     		name = dev->name;
    @@ -365,7 +376,9 @@ static int uinput_create_device(struct uinput_device *udev)
     	if (error)
     		goto fail2;
     
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_CREATED;
    +	spin_unlock(&udev->state_lock);
     
     	return 0;
     
    @@ -383,6 +396,7 @@ static int uinput_open(struct inode *inode, struct file *file)
     		return -ENOMEM;
     
     	mutex_init(&newdev->mutex);
    +	spin_lock_init(&newdev->state_lock);
     	spin_lock_init(&newdev->requests_lock);
     	init_waitqueue_head(&newdev->requests_waitq);
     	init_waitqueue_head(&newdev->waitq);
    -- 
    cgit 1.3-korg
    
    
    
271ee71a1917

Input: uinput - fix circular locking dependency with ff-core

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitMikhail GavrilovFixed in 5.15.203via kernel-cna
1 file changed · +21 8
  • drivers/input/misc/uinput.c+21 8 modified
    diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
    index faed4590a8a92..bd8be236af756 100644
    --- a/drivers/input/misc/uinput.c
    +++ b/drivers/input/misc/uinput.c
    @@ -56,6 +56,7 @@ struct uinput_device {
     	struct input_dev	*dev;
     	struct mutex		mutex;
     	enum uinput_state	state;
    +	spinlock_t		state_lock;
     	wait_queue_head_t	waitq;
     	unsigned char		ready;
     	unsigned char		head;
    @@ -145,19 +146,15 @@ static void uinput_request_release_slot(struct uinput_device *udev,
     static int uinput_request_send(struct uinput_device *udev,
     			       struct uinput_request *request)
     {
    -	int retval;
    +	int retval = 0;
     
    -	retval = mutex_lock_interruptible(&udev->mutex);
    -	if (retval)
    -		return retval;
    +	spin_lock(&udev->state_lock);
     
     	if (udev->state != UIST_CREATED) {
     		retval = -ENODEV;
     		goto out;
     	}
     
    -	init_completion(&request->done);
    -
     	/*
     	 * Tell our userspace application about this new request
     	 * by queueing an input event.
    @@ -165,7 +162,7 @@ static int uinput_request_send(struct uinput_device *udev,
     	uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
     
      out:
    -	mutex_unlock(&udev->mutex);
    +	spin_unlock(&udev->state_lock);
     	return retval;
     }
     
    @@ -174,6 +171,13 @@ static int uinput_request_submit(struct uinput_device *udev,
     {
     	int retval;
     
    +	/*
    +	 * Initialize completion before allocating the request slot.
    +	 * Once the slot is allocated, uinput_flush_requests() may
    +	 * complete it at any time, so it must be initialized first.
    +	 */
    +	init_completion(&request->done);
    +
     	retval = uinput_request_reserve_slot(udev, request);
     	if (retval)
     		return retval;
    @@ -288,7 +292,14 @@ static void uinput_destroy_device(struct uinput_device *udev)
     	struct input_dev *dev = udev->dev;
     	enum uinput_state old_state = udev->state;
     
    +	/*
    +	 * Update state under state_lock so that concurrent
    +	 * uinput_request_send() sees the state change before we
    +	 * flush pending requests and tear down the device.
    +	 */
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_NEW_DEVICE;
    +	spin_unlock(&udev->state_lock);
     
     	if (dev) {
     		name = dev->name;
    @@ -365,7 +376,9 @@ static int uinput_create_device(struct uinput_device *udev)
     	if (error)
     		goto fail2;
     
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_CREATED;
    +	spin_unlock(&udev->state_lock);
     
     	return 0;
     
    @@ -383,6 +396,7 @@ static int uinput_open(struct inode *inode, struct file *file)
     		return -ENOMEM;
     
     	mutex_init(&newdev->mutex);
    +	spin_lock_init(&newdev->state_lock);
     	spin_lock_init(&newdev->requests_lock);
     	init_waitqueue_head(&newdev->requests_waitq);
     	init_waitqueue_head(&newdev->waitq);
    -- 
    cgit 1.3-korg
    
    
    
71a9729f412e

Input: uinput - fix circular locking dependency with ff-core

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitMikhail GavrilovFixed in 5.10.253via kernel-cna
1 file changed · +21 8
  • drivers/input/misc/uinput.c+21 8 modified
    diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
    index faed4590a8a92..bd8be236af756 100644
    --- a/drivers/input/misc/uinput.c
    +++ b/drivers/input/misc/uinput.c
    @@ -56,6 +56,7 @@ struct uinput_device {
     	struct input_dev	*dev;
     	struct mutex		mutex;
     	enum uinput_state	state;
    +	spinlock_t		state_lock;
     	wait_queue_head_t	waitq;
     	unsigned char		ready;
     	unsigned char		head;
    @@ -145,19 +146,15 @@ static void uinput_request_release_slot(struct uinput_device *udev,
     static int uinput_request_send(struct uinput_device *udev,
     			       struct uinput_request *request)
     {
    -	int retval;
    +	int retval = 0;
     
    -	retval = mutex_lock_interruptible(&udev->mutex);
    -	if (retval)
    -		return retval;
    +	spin_lock(&udev->state_lock);
     
     	if (udev->state != UIST_CREATED) {
     		retval = -ENODEV;
     		goto out;
     	}
     
    -	init_completion(&request->done);
    -
     	/*
     	 * Tell our userspace application about this new request
     	 * by queueing an input event.
    @@ -165,7 +162,7 @@ static int uinput_request_send(struct uinput_device *udev,
     	uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
     
      out:
    -	mutex_unlock(&udev->mutex);
    +	spin_unlock(&udev->state_lock);
     	return retval;
     }
     
    @@ -174,6 +171,13 @@ static int uinput_request_submit(struct uinput_device *udev,
     {
     	int retval;
     
    +	/*
    +	 * Initialize completion before allocating the request slot.
    +	 * Once the slot is allocated, uinput_flush_requests() may
    +	 * complete it at any time, so it must be initialized first.
    +	 */
    +	init_completion(&request->done);
    +
     	retval = uinput_request_reserve_slot(udev, request);
     	if (retval)
     		return retval;
    @@ -288,7 +292,14 @@ static void uinput_destroy_device(struct uinput_device *udev)
     	struct input_dev *dev = udev->dev;
     	enum uinput_state old_state = udev->state;
     
    +	/*
    +	 * Update state under state_lock so that concurrent
    +	 * uinput_request_send() sees the state change before we
    +	 * flush pending requests and tear down the device.
    +	 */
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_NEW_DEVICE;
    +	spin_unlock(&udev->state_lock);
     
     	if (dev) {
     		name = dev->name;
    @@ -365,7 +376,9 @@ static int uinput_create_device(struct uinput_device *udev)
     	if (error)
     		goto fail2;
     
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_CREATED;
    +	spin_unlock(&udev->state_lock);
     
     	return 0;
     
    @@ -383,6 +396,7 @@ static int uinput_open(struct inode *inode, struct file *file)
     		return -ENOMEM;
     
     	mutex_init(&newdev->mutex);
    +	spin_lock_init(&newdev->state_lock);
     	spin_lock_init(&newdev->requests_lock);
     	init_waitqueue_head(&newdev->requests_waitq);
     	init_waitqueue_head(&newdev->waitq);
    -- 
    cgit 1.3-korg
    
    
    
4cda78d6f8bf

Input: uinput - fix circular locking dependency with ff-core

1 file changed · +21 8
  • drivers/input/misc/uinput.c+21 8 modified
    diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
    index 13336a2fd49c8..a973e82205b5c 100644
    --- a/drivers/input/misc/uinput.c
    +++ b/drivers/input/misc/uinput.c
    @@ -57,6 +57,7 @@ struct uinput_device {
     	struct input_dev	*dev;
     	struct mutex		mutex;
     	enum uinput_state	state;
    +	spinlock_t		state_lock;
     	wait_queue_head_t	waitq;
     	unsigned char		ready;
     	unsigned char		head;
    @@ -146,19 +147,15 @@ static void uinput_request_release_slot(struct uinput_device *udev,
     static int uinput_request_send(struct uinput_device *udev,
     			       struct uinput_request *request)
     {
    -	int retval;
    +	int retval = 0;
     
    -	retval = mutex_lock_interruptible(&udev->mutex);
    -	if (retval)
    -		return retval;
    +	spin_lock(&udev->state_lock);
     
     	if (udev->state != UIST_CREATED) {
     		retval = -ENODEV;
     		goto out;
     	}
     
    -	init_completion(&request->done);
    -
     	/*
     	 * Tell our userspace application about this new request
     	 * by queueing an input event.
    @@ -166,7 +163,7 @@ static int uinput_request_send(struct uinput_device *udev,
     	uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
     
      out:
    -	mutex_unlock(&udev->mutex);
    +	spin_unlock(&udev->state_lock);
     	return retval;
     }
     
    @@ -175,6 +172,13 @@ static int uinput_request_submit(struct uinput_device *udev,
     {
     	int retval;
     
    +	/*
    +	 * Initialize completion before allocating the request slot.
    +	 * Once the slot is allocated, uinput_flush_requests() may
    +	 * complete it at any time, so it must be initialized first.
    +	 */
    +	init_completion(&request->done);
    +
     	retval = uinput_request_reserve_slot(udev, request);
     	if (retval)
     		return retval;
    @@ -289,7 +293,14 @@ static void uinput_destroy_device(struct uinput_device *udev)
     	struct input_dev *dev = udev->dev;
     	enum uinput_state old_state = udev->state;
     
    +	/*
    +	 * Update state under state_lock so that concurrent
    +	 * uinput_request_send() sees the state change before we
    +	 * flush pending requests and tear down the device.
    +	 */
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_NEW_DEVICE;
    +	spin_unlock(&udev->state_lock);
     
     	if (dev) {
     		name = dev->name;
    @@ -366,7 +377,9 @@ static int uinput_create_device(struct uinput_device *udev)
     	if (error)
     		goto fail2;
     
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_CREATED;
    +	spin_unlock(&udev->state_lock);
     
     	return 0;
     
    @@ -384,6 +397,7 @@ static int uinput_open(struct inode *inode, struct file *file)
     		return -ENOMEM;
     
     	mutex_init(&newdev->mutex);
    +	spin_lock_init(&newdev->state_lock);
     	spin_lock_init(&newdev->requests_lock);
     	init_waitqueue_head(&newdev->requests_waitq);
     	init_waitqueue_head(&newdev->waitq);
    -- 
    cgit 1.3-korg
    
    
    
a3d6c9c053c9

Input: uinput - fix circular locking dependency with ff-core

1 file changed · +21 8
  • drivers/input/misc/uinput.c+21 8 modified
    diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
    index 13336a2fd49c8..a973e82205b5c 100644
    --- a/drivers/input/misc/uinput.c
    +++ b/drivers/input/misc/uinput.c
    @@ -57,6 +57,7 @@ struct uinput_device {
     	struct input_dev	*dev;
     	struct mutex		mutex;
     	enum uinput_state	state;
    +	spinlock_t		state_lock;
     	wait_queue_head_t	waitq;
     	unsigned char		ready;
     	unsigned char		head;
    @@ -146,19 +147,15 @@ static void uinput_request_release_slot(struct uinput_device *udev,
     static int uinput_request_send(struct uinput_device *udev,
     			       struct uinput_request *request)
     {
    -	int retval;
    +	int retval = 0;
     
    -	retval = mutex_lock_interruptible(&udev->mutex);
    -	if (retval)
    -		return retval;
    +	spin_lock(&udev->state_lock);
     
     	if (udev->state != UIST_CREATED) {
     		retval = -ENODEV;
     		goto out;
     	}
     
    -	init_completion(&request->done);
    -
     	/*
     	 * Tell our userspace application about this new request
     	 * by queueing an input event.
    @@ -166,7 +163,7 @@ static int uinput_request_send(struct uinput_device *udev,
     	uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
     
      out:
    -	mutex_unlock(&udev->mutex);
    +	spin_unlock(&udev->state_lock);
     	return retval;
     }
     
    @@ -175,6 +172,13 @@ static int uinput_request_submit(struct uinput_device *udev,
     {
     	int retval;
     
    +	/*
    +	 * Initialize completion before allocating the request slot.
    +	 * Once the slot is allocated, uinput_flush_requests() may
    +	 * complete it at any time, so it must be initialized first.
    +	 */
    +	init_completion(&request->done);
    +
     	retval = uinput_request_reserve_slot(udev, request);
     	if (retval)
     		return retval;
    @@ -289,7 +293,14 @@ static void uinput_destroy_device(struct uinput_device *udev)
     	struct input_dev *dev = udev->dev;
     	enum uinput_state old_state = udev->state;
     
    +	/*
    +	 * Update state under state_lock so that concurrent
    +	 * uinput_request_send() sees the state change before we
    +	 * flush pending requests and tear down the device.
    +	 */
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_NEW_DEVICE;
    +	spin_unlock(&udev->state_lock);
     
     	if (dev) {
     		name = dev->name;
    @@ -366,7 +377,9 @@ static int uinput_create_device(struct uinput_device *udev)
     	if (error)
     		goto fail2;
     
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_CREATED;
    +	spin_unlock(&udev->state_lock);
     
     	return 0;
     
    @@ -384,6 +397,7 @@ static int uinput_open(struct inode *inode, struct file *file)
     		return -ENOMEM;
     
     	mutex_init(&newdev->mutex);
    +	spin_lock_init(&newdev->state_lock);
     	spin_lock_init(&newdev->requests_lock);
     	init_waitqueue_head(&newdev->requests_waitq);
     	init_waitqueue_head(&newdev->waitq);
    -- 
    cgit 1.3-korg
    
    
    
974f7b138c3a

Input: uinput - fix circular locking dependency with ff-core

1 file changed · +21 8
  • drivers/input/misc/uinput.c+21 8 modified
    diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
    index faed4590a8a92..bd8be236af756 100644
    --- a/drivers/input/misc/uinput.c
    +++ b/drivers/input/misc/uinput.c
    @@ -56,6 +56,7 @@ struct uinput_device {
     	struct input_dev	*dev;
     	struct mutex		mutex;
     	enum uinput_state	state;
    +	spinlock_t		state_lock;
     	wait_queue_head_t	waitq;
     	unsigned char		ready;
     	unsigned char		head;
    @@ -145,19 +146,15 @@ static void uinput_request_release_slot(struct uinput_device *udev,
     static int uinput_request_send(struct uinput_device *udev,
     			       struct uinput_request *request)
     {
    -	int retval;
    +	int retval = 0;
     
    -	retval = mutex_lock_interruptible(&udev->mutex);
    -	if (retval)
    -		return retval;
    +	spin_lock(&udev->state_lock);
     
     	if (udev->state != UIST_CREATED) {
     		retval = -ENODEV;
     		goto out;
     	}
     
    -	init_completion(&request->done);
    -
     	/*
     	 * Tell our userspace application about this new request
     	 * by queueing an input event.
    @@ -165,7 +162,7 @@ static int uinput_request_send(struct uinput_device *udev,
     	uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
     
      out:
    -	mutex_unlock(&udev->mutex);
    +	spin_unlock(&udev->state_lock);
     	return retval;
     }
     
    @@ -174,6 +171,13 @@ static int uinput_request_submit(struct uinput_device *udev,
     {
     	int retval;
     
    +	/*
    +	 * Initialize completion before allocating the request slot.
    +	 * Once the slot is allocated, uinput_flush_requests() may
    +	 * complete it at any time, so it must be initialized first.
    +	 */
    +	init_completion(&request->done);
    +
     	retval = uinput_request_reserve_slot(udev, request);
     	if (retval)
     		return retval;
    @@ -288,7 +292,14 @@ static void uinput_destroy_device(struct uinput_device *udev)
     	struct input_dev *dev = udev->dev;
     	enum uinput_state old_state = udev->state;
     
    +	/*
    +	 * Update state under state_lock so that concurrent
    +	 * uinput_request_send() sees the state change before we
    +	 * flush pending requests and tear down the device.
    +	 */
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_NEW_DEVICE;
    +	spin_unlock(&udev->state_lock);
     
     	if (dev) {
     		name = dev->name;
    @@ -365,7 +376,9 @@ static int uinput_create_device(struct uinput_device *udev)
     	if (error)
     		goto fail2;
     
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_CREATED;
    +	spin_unlock(&udev->state_lock);
     
     	return 0;
     
    @@ -383,6 +396,7 @@ static int uinput_open(struct inode *inode, struct file *file)
     		return -ENOMEM;
     
     	mutex_init(&newdev->mutex);
    +	spin_lock_init(&newdev->state_lock);
     	spin_lock_init(&newdev->requests_lock);
     	init_waitqueue_head(&newdev->requests_waitq);
     	init_waitqueue_head(&newdev->waitq);
    -- 
    cgit 1.3-korg
    
    
    
71a9729f412e

Input: uinput - fix circular locking dependency with ff-core

1 file changed · +21 8
  • drivers/input/misc/uinput.c+21 8 modified
    diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
    index faed4590a8a92..bd8be236af756 100644
    --- a/drivers/input/misc/uinput.c
    +++ b/drivers/input/misc/uinput.c
    @@ -56,6 +56,7 @@ struct uinput_device {
     	struct input_dev	*dev;
     	struct mutex		mutex;
     	enum uinput_state	state;
    +	spinlock_t		state_lock;
     	wait_queue_head_t	waitq;
     	unsigned char		ready;
     	unsigned char		head;
    @@ -145,19 +146,15 @@ static void uinput_request_release_slot(struct uinput_device *udev,
     static int uinput_request_send(struct uinput_device *udev,
     			       struct uinput_request *request)
     {
    -	int retval;
    +	int retval = 0;
     
    -	retval = mutex_lock_interruptible(&udev->mutex);
    -	if (retval)
    -		return retval;
    +	spin_lock(&udev->state_lock);
     
     	if (udev->state != UIST_CREATED) {
     		retval = -ENODEV;
     		goto out;
     	}
     
    -	init_completion(&request->done);
    -
     	/*
     	 * Tell our userspace application about this new request
     	 * by queueing an input event.
    @@ -165,7 +162,7 @@ static int uinput_request_send(struct uinput_device *udev,
     	uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
     
      out:
    -	mutex_unlock(&udev->mutex);
    +	spin_unlock(&udev->state_lock);
     	return retval;
     }
     
    @@ -174,6 +171,13 @@ static int uinput_request_submit(struct uinput_device *udev,
     {
     	int retval;
     
    +	/*
    +	 * Initialize completion before allocating the request slot.
    +	 * Once the slot is allocated, uinput_flush_requests() may
    +	 * complete it at any time, so it must be initialized first.
    +	 */
    +	init_completion(&request->done);
    +
     	retval = uinput_request_reserve_slot(udev, request);
     	if (retval)
     		return retval;
    @@ -288,7 +292,14 @@ static void uinput_destroy_device(struct uinput_device *udev)
     	struct input_dev *dev = udev->dev;
     	enum uinput_state old_state = udev->state;
     
    +	/*
    +	 * Update state under state_lock so that concurrent
    +	 * uinput_request_send() sees the state change before we
    +	 * flush pending requests and tear down the device.
    +	 */
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_NEW_DEVICE;
    +	spin_unlock(&udev->state_lock);
     
     	if (dev) {
     		name = dev->name;
    @@ -365,7 +376,9 @@ static int uinput_create_device(struct uinput_device *udev)
     	if (error)
     		goto fail2;
     
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_CREATED;
    +	spin_unlock(&udev->state_lock);
     
     	return 0;
     
    @@ -383,6 +396,7 @@ static int uinput_open(struct inode *inode, struct file *file)
     		return -ENOMEM;
     
     	mutex_init(&newdev->mutex);
    +	spin_lock_init(&newdev->state_lock);
     	spin_lock_init(&newdev->requests_lock);
     	init_waitqueue_head(&newdev->requests_waitq);
     	init_waitqueue_head(&newdev->waitq);
    -- 
    cgit 1.3-korg
    
    
    
546c18a14924

Input: uinput - fix circular locking dependency with ff-core

1 file changed · +21 8
  • drivers/input/misc/uinput.c+21 8 modified
    diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
    index edb62a284548b..fd624c35a328f 100644
    --- a/drivers/input/misc/uinput.c
    +++ b/drivers/input/misc/uinput.c
    @@ -57,6 +57,7 @@ struct uinput_device {
     	struct input_dev	*dev;
     	struct mutex		mutex;
     	enum uinput_state	state;
    +	spinlock_t		state_lock;
     	wait_queue_head_t	waitq;
     	unsigned char		ready;
     	unsigned char		head;
    @@ -146,19 +147,15 @@ static void uinput_request_release_slot(struct uinput_device *udev,
     static int uinput_request_send(struct uinput_device *udev,
     			       struct uinput_request *request)
     {
    -	int retval;
    +	int retval = 0;
     
    -	retval = mutex_lock_interruptible(&udev->mutex);
    -	if (retval)
    -		return retval;
    +	spin_lock(&udev->state_lock);
     
     	if (udev->state != UIST_CREATED) {
     		retval = -ENODEV;
     		goto out;
     	}
     
    -	init_completion(&request->done);
    -
     	/*
     	 * Tell our userspace application about this new request
     	 * by queueing an input event.
    @@ -166,7 +163,7 @@ static int uinput_request_send(struct uinput_device *udev,
     	uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
     
      out:
    -	mutex_unlock(&udev->mutex);
    +	spin_unlock(&udev->state_lock);
     	return retval;
     }
     
    @@ -175,6 +172,13 @@ static int uinput_request_submit(struct uinput_device *udev,
     {
     	int retval;
     
    +	/*
    +	 * Initialize completion before allocating the request slot.
    +	 * Once the slot is allocated, uinput_flush_requests() may
    +	 * complete it at any time, so it must be initialized first.
    +	 */
    +	init_completion(&request->done);
    +
     	retval = uinput_request_reserve_slot(udev, request);
     	if (retval)
     		return retval;
    @@ -289,7 +293,14 @@ static void uinput_destroy_device(struct uinput_device *udev)
     	struct input_dev *dev = udev->dev;
     	enum uinput_state old_state = udev->state;
     
    +	/*
    +	 * Update state under state_lock so that concurrent
    +	 * uinput_request_send() sees the state change before we
    +	 * flush pending requests and tear down the device.
    +	 */
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_NEW_DEVICE;
    +	spin_unlock(&udev->state_lock);
     
     	if (dev) {
     		name = dev->name;
    @@ -366,7 +377,9 @@ static int uinput_create_device(struct uinput_device *udev)
     	if (error)
     		goto fail2;
     
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_CREATED;
    +	spin_unlock(&udev->state_lock);
     
     	return 0;
     
    @@ -384,6 +397,7 @@ static int uinput_open(struct inode *inode, struct file *file)
     		return -ENOMEM;
     
     	mutex_init(&newdev->mutex);
    +	spin_lock_init(&newdev->state_lock);
     	spin_lock_init(&newdev->requests_lock);
     	init_waitqueue_head(&newdev->requests_waitq);
     	init_waitqueue_head(&newdev->waitq);
    -- 
    cgit 1.3-korg
    
    
    
271ee71a1917

Input: uinput - fix circular locking dependency with ff-core

1 file changed · +21 8
  • drivers/input/misc/uinput.c+21 8 modified
    diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
    index faed4590a8a92..bd8be236af756 100644
    --- a/drivers/input/misc/uinput.c
    +++ b/drivers/input/misc/uinput.c
    @@ -56,6 +56,7 @@ struct uinput_device {
     	struct input_dev	*dev;
     	struct mutex		mutex;
     	enum uinput_state	state;
    +	spinlock_t		state_lock;
     	wait_queue_head_t	waitq;
     	unsigned char		ready;
     	unsigned char		head;
    @@ -145,19 +146,15 @@ static void uinput_request_release_slot(struct uinput_device *udev,
     static int uinput_request_send(struct uinput_device *udev,
     			       struct uinput_request *request)
     {
    -	int retval;
    +	int retval = 0;
     
    -	retval = mutex_lock_interruptible(&udev->mutex);
    -	if (retval)
    -		return retval;
    +	spin_lock(&udev->state_lock);
     
     	if (udev->state != UIST_CREATED) {
     		retval = -ENODEV;
     		goto out;
     	}
     
    -	init_completion(&request->done);
    -
     	/*
     	 * Tell our userspace application about this new request
     	 * by queueing an input event.
    @@ -165,7 +162,7 @@ static int uinput_request_send(struct uinput_device *udev,
     	uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
     
      out:
    -	mutex_unlock(&udev->mutex);
    +	spin_unlock(&udev->state_lock);
     	return retval;
     }
     
    @@ -174,6 +171,13 @@ static int uinput_request_submit(struct uinput_device *udev,
     {
     	int retval;
     
    +	/*
    +	 * Initialize completion before allocating the request slot.
    +	 * Once the slot is allocated, uinput_flush_requests() may
    +	 * complete it at any time, so it must be initialized first.
    +	 */
    +	init_completion(&request->done);
    +
     	retval = uinput_request_reserve_slot(udev, request);
     	if (retval)
     		return retval;
    @@ -288,7 +292,14 @@ static void uinput_destroy_device(struct uinput_device *udev)
     	struct input_dev *dev = udev->dev;
     	enum uinput_state old_state = udev->state;
     
    +	/*
    +	 * Update state under state_lock so that concurrent
    +	 * uinput_request_send() sees the state change before we
    +	 * flush pending requests and tear down the device.
    +	 */
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_NEW_DEVICE;
    +	spin_unlock(&udev->state_lock);
     
     	if (dev) {
     		name = dev->name;
    @@ -365,7 +376,9 @@ static int uinput_create_device(struct uinput_device *udev)
     	if (error)
     		goto fail2;
     
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_CREATED;
    +	spin_unlock(&udev->state_lock);
     
     	return 0;
     
    @@ -383,6 +396,7 @@ static int uinput_open(struct inode *inode, struct file *file)
     		return -ENOMEM;
     
     	mutex_init(&newdev->mutex);
    +	spin_lock_init(&newdev->state_lock);
     	spin_lock_init(&newdev->requests_lock);
     	init_waitqueue_head(&newdev->requests_waitq);
     	init_waitqueue_head(&newdev->waitq);
    -- 
    cgit 1.3-korg
    
    
    
1e09dfbb4f5d

Input: uinput - fix circular locking dependency with ff-core

1 file changed · +21 8
  • drivers/input/misc/uinput.c+21 8 modified
    diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
    index 13336a2fd49c8..a973e82205b5c 100644
    --- a/drivers/input/misc/uinput.c
    +++ b/drivers/input/misc/uinput.c
    @@ -57,6 +57,7 @@ struct uinput_device {
     	struct input_dev	*dev;
     	struct mutex		mutex;
     	enum uinput_state	state;
    +	spinlock_t		state_lock;
     	wait_queue_head_t	waitq;
     	unsigned char		ready;
     	unsigned char		head;
    @@ -146,19 +147,15 @@ static void uinput_request_release_slot(struct uinput_device *udev,
     static int uinput_request_send(struct uinput_device *udev,
     			       struct uinput_request *request)
     {
    -	int retval;
    +	int retval = 0;
     
    -	retval = mutex_lock_interruptible(&udev->mutex);
    -	if (retval)
    -		return retval;
    +	spin_lock(&udev->state_lock);
     
     	if (udev->state != UIST_CREATED) {
     		retval = -ENODEV;
     		goto out;
     	}
     
    -	init_completion(&request->done);
    -
     	/*
     	 * Tell our userspace application about this new request
     	 * by queueing an input event.
    @@ -166,7 +163,7 @@ static int uinput_request_send(struct uinput_device *udev,
     	uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
     
      out:
    -	mutex_unlock(&udev->mutex);
    +	spin_unlock(&udev->state_lock);
     	return retval;
     }
     
    @@ -175,6 +172,13 @@ static int uinput_request_submit(struct uinput_device *udev,
     {
     	int retval;
     
    +	/*
    +	 * Initialize completion before allocating the request slot.
    +	 * Once the slot is allocated, uinput_flush_requests() may
    +	 * complete it at any time, so it must be initialized first.
    +	 */
    +	init_completion(&request->done);
    +
     	retval = uinput_request_reserve_slot(udev, request);
     	if (retval)
     		return retval;
    @@ -289,7 +293,14 @@ static void uinput_destroy_device(struct uinput_device *udev)
     	struct input_dev *dev = udev->dev;
     	enum uinput_state old_state = udev->state;
     
    +	/*
    +	 * Update state under state_lock so that concurrent
    +	 * uinput_request_send() sees the state change before we
    +	 * flush pending requests and tear down the device.
    +	 */
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_NEW_DEVICE;
    +	spin_unlock(&udev->state_lock);
     
     	if (dev) {
     		name = dev->name;
    @@ -366,7 +377,9 @@ static int uinput_create_device(struct uinput_device *udev)
     	if (error)
     		goto fail2;
     
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_CREATED;
    +	spin_unlock(&udev->state_lock);
     
     	return 0;
     
    @@ -384,6 +397,7 @@ static int uinput_open(struct inode *inode, struct file *file)
     		return -ENOMEM;
     
     	mutex_init(&newdev->mutex);
    +	spin_lock_init(&newdev->state_lock);
     	spin_lock_init(&newdev->requests_lock);
     	init_waitqueue_head(&newdev->requests_waitq);
     	init_waitqueue_head(&newdev->waitq);
    -- 
    cgit 1.3-korg
    
    
    
1534661043c4

Input: uinput - fix circular locking dependency with ff-core

1 file changed · +21 8
  • drivers/input/misc/uinput.c+21 8 modified
    diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
    index 13336a2fd49c8..a973e82205b5c 100644
    --- a/drivers/input/misc/uinput.c
    +++ b/drivers/input/misc/uinput.c
    @@ -57,6 +57,7 @@ struct uinput_device {
     	struct input_dev	*dev;
     	struct mutex		mutex;
     	enum uinput_state	state;
    +	spinlock_t		state_lock;
     	wait_queue_head_t	waitq;
     	unsigned char		ready;
     	unsigned char		head;
    @@ -146,19 +147,15 @@ static void uinput_request_release_slot(struct uinput_device *udev,
     static int uinput_request_send(struct uinput_device *udev,
     			       struct uinput_request *request)
     {
    -	int retval;
    +	int retval = 0;
     
    -	retval = mutex_lock_interruptible(&udev->mutex);
    -	if (retval)
    -		return retval;
    +	spin_lock(&udev->state_lock);
     
     	if (udev->state != UIST_CREATED) {
     		retval = -ENODEV;
     		goto out;
     	}
     
    -	init_completion(&request->done);
    -
     	/*
     	 * Tell our userspace application about this new request
     	 * by queueing an input event.
    @@ -166,7 +163,7 @@ static int uinput_request_send(struct uinput_device *udev,
     	uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id);
     
      out:
    -	mutex_unlock(&udev->mutex);
    +	spin_unlock(&udev->state_lock);
     	return retval;
     }
     
    @@ -175,6 +172,13 @@ static int uinput_request_submit(struct uinput_device *udev,
     {
     	int retval;
     
    +	/*
    +	 * Initialize completion before allocating the request slot.
    +	 * Once the slot is allocated, uinput_flush_requests() may
    +	 * complete it at any time, so it must be initialized first.
    +	 */
    +	init_completion(&request->done);
    +
     	retval = uinput_request_reserve_slot(udev, request);
     	if (retval)
     		return retval;
    @@ -289,7 +293,14 @@ static void uinput_destroy_device(struct uinput_device *udev)
     	struct input_dev *dev = udev->dev;
     	enum uinput_state old_state = udev->state;
     
    +	/*
    +	 * Update state under state_lock so that concurrent
    +	 * uinput_request_send() sees the state change before we
    +	 * flush pending requests and tear down the device.
    +	 */
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_NEW_DEVICE;
    +	spin_unlock(&udev->state_lock);
     
     	if (dev) {
     		name = dev->name;
    @@ -366,7 +377,9 @@ static int uinput_create_device(struct uinput_device *udev)
     	if (error)
     		goto fail2;
     
    +	spin_lock(&udev->state_lock);
     	udev->state = UIST_CREATED;
    +	spin_unlock(&udev->state_lock);
     
     	return 0;
     
    @@ -384,6 +397,7 @@ static int uinput_open(struct inode *inode, struct file *file)
     		return -ENOMEM;
     
     	mutex_init(&newdev->mutex);
    +	spin_lock_init(&newdev->state_lock);
     	spin_lock_init(&newdev->requests_lock);
     	init_waitqueue_head(&newdev->requests_waitq);
     	init_waitqueue_head(&newdev->waitq);
    -- 
    cgit 1.3-korg
    
    
    

Vulnerability mechanics

Synthesis attempt was rejected by the grounding validator. Re-run pending.

References

8

News mentions

0

No linked articles in our index yet.