Skip to content

Commit 26c08da

Browse files
Chenghai Huanggregkh
authored andcommitted
uacce: ensure safe queue release with state management
Directly calling `put_queue` carries risks since it cannot guarantee that resources of `uacce_queue` have been fully released beforehand. So adding a `stop_queue` operation for the UACCE_CMD_PUT_Q command and leaving the `put_queue` operation to the final resource release ensures safety. Queue states are defined as follows: - UACCE_Q_ZOMBIE: Initial state - UACCE_Q_INIT: After opening `uacce` - UACCE_Q_STARTED: After `start` is issued via `ioctl` When executing `poweroff -f` in virt while accelerator are still working, `uacce_fops_release` and `uacce_remove` may execute concurrently. This can cause `uacce_put_queue` within `uacce_fops_release` to access a NULL `ops` pointer. Therefore, add state checks to prevent accessing freed pointers. Fixes: 015d239 ("uacce: add uacce driver") Cc: stable@vger.kernel.org Signed-off-by: Chenghai Huang <huangchenghai2@huawei.com> Signed-off-by: Yang Shen <shenyang39@huawei.com> Acked-by: Zhangfei Gao <zhangfei.gao@linaro.org> Link: https://patch.msgid.link/20251202061256.4158641-5-huangchenghai2@huawei.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 0269534 commit 26c08da

1 file changed

Lines changed: 21 additions & 7 deletions

File tree

drivers/misc/uacce/uacce.c

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,20 +40,34 @@ static int uacce_start_queue(struct uacce_queue *q)
4040
return 0;
4141
}
4242

43-
static int uacce_put_queue(struct uacce_queue *q)
43+
static int uacce_stop_queue(struct uacce_queue *q)
4444
{
4545
struct uacce_device *uacce = q->uacce;
4646

47-
if ((q->state == UACCE_Q_STARTED) && uacce->ops->stop_queue)
47+
if (q->state != UACCE_Q_STARTED)
48+
return 0;
49+
50+
if (uacce->ops->stop_queue)
4851
uacce->ops->stop_queue(q);
4952

50-
if ((q->state == UACCE_Q_INIT || q->state == UACCE_Q_STARTED) &&
51-
uacce->ops->put_queue)
53+
q->state = UACCE_Q_INIT;
54+
55+
return 0;
56+
}
57+
58+
static void uacce_put_queue(struct uacce_queue *q)
59+
{
60+
struct uacce_device *uacce = q->uacce;
61+
62+
uacce_stop_queue(q);
63+
64+
if (q->state != UACCE_Q_INIT)
65+
return;
66+
67+
if (uacce->ops->put_queue)
5268
uacce->ops->put_queue(q);
5369

5470
q->state = UACCE_Q_ZOMBIE;
55-
56-
return 0;
5771
}
5872

5973
static long uacce_fops_unl_ioctl(struct file *filep,
@@ -80,7 +94,7 @@ static long uacce_fops_unl_ioctl(struct file *filep,
8094
ret = uacce_start_queue(q);
8195
break;
8296
case UACCE_CMD_PUT_Q:
83-
ret = uacce_put_queue(q);
97+
ret = uacce_stop_queue(q);
8498
break;
8599
default:
86100
if (uacce->ops->ioctl)

0 commit comments

Comments
 (0)