From 2069218ebbdf83815d1104b941116cb9f52dec0b Mon Sep 17 00:00:00 2001 From: Aleksa Savic Date: Wed, 10 Jan 2024 19:25:21 +0100 Subject: [PATCH] nzxt-kraken3: Protect completions in raw event parsing with main spinlock Through hidraw, userspace can cause a status report to be sent from the device. The parsing in kraken3_raw_event() may happen in parallel to a kraken3_get_status() call (which resets the completion for tracking the report) if it's running on a different CPU where bottom half interrupts are not disabled. Add spin_lock() calls around the completions to prevent race issues. Reference: https://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging.git/commit/drivers/hwmon/gigabyte_waterforce.c?h=hwmon-next&id=41c71105a845ec1458680f01644d032a5fbbe0d9 While at it, wrap the Z53 complete_all() with a completion_done(). Signed-off-by: Aleksa Savic --- nzxt-kraken3.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/nzxt-kraken3.c b/nzxt-kraken3.c index e0149d4..5806a3f 100644 --- a/nzxt-kraken3.c +++ b/nzxt-kraken3.c @@ -750,10 +750,12 @@ static int kraken3_raw_event(struct hid_device *hdev, struct hid_report *report, * Mark first X-series device report as received, * as well as all for Z-series, if faulty. */ + spin_lock(&priv->status_completion_lock); if (priv->kind != X53 || !completion_done(&priv->status_report_processed)) { priv->is_device_faulty = true; complete_all(&priv->status_report_processed); } + spin_unlock(&priv->status_completion_lock); return 0; } @@ -768,18 +770,20 @@ static int kraken3_raw_event(struct hid_device *hdev, struct hid_report *report, priv->fan_input[0] = get_unaligned_le16(data + PUMP_SPEED_OFFSET); priv->channel_info[0].reported_duty = kraken3_percent_to_pwm(data[PUMP_DUTY_OFFSET]); - /* Mark first X-series device report as received */ - if (priv->kind == X53 && !completion_done(&priv->status_report_processed)) + spin_lock(&priv->status_completion_lock); + if (priv->kind == X53 && !completion_done(&priv->status_report_processed)) { + /* Mark first X-series device report as received */ complete_all(&priv->status_report_processed); - - /* Additional readings for Z53 */ - if (priv->kind == Z53) { + } else if (priv->kind == Z53) { + /* Additional readings for Z53 */ priv->fan_input[1] = get_unaligned_le16(data + Z53_FAN_SPEED_OFFSET); priv->channel_info[1].reported_duty = kraken3_percent_to_pwm(data[Z53_FAN_DUTY_OFFSET]); - complete_all(&priv->status_report_processed); + if (!completion_done(&priv->status_report_processed)) + complete_all(&priv->status_report_processed); } + spin_unlock(&priv->status_completion_lock); priv->updated = jiffies;