From nobody Sat Jul 25 23:42:05 2026 Received: from mail-wm1-f51.google.com (mail-wm1-f51.google.com [209.85.128.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3BB70243367 for ; Sat, 11 Jul 2026 08:03:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783757036; cv=none; b=bVmLIdhEDvuDuFmLx9eTuY3kc3tamW1i68L306JycJog3M0zMofTQz6LgO6NnYQiBZFfeSMWCxGZ6DBh/3EjBex0p+J1zp5kg4GBT6foUNbeNcEE/Y3XtmIdVuQYYRYnZyDa3XsKHRBza0H04mFMicYxyXqI/f2Mxluu2MuC1sc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783757036; c=relaxed/simple; bh=ql13UOHrnBdmGaJDsZKTfQSxuOew+yEFAJD0Ih34BZA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SAOnI0J4YJ7i3CYHd6eCyzb9O685ex0v2e+efdrcfWWtzikIQw3rCPutydLxxEJQ1Rh3eXrGl+u9pd83Bh9CtTDjJWQMPCgfludoDaVJx0m7MStOuorW0b98TmiZiLLNBAXGW4YbSLcPj1qmYMDclMd3/rlc9fEB/Ug/wsr00Eo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=0sec.ai; spf=pass smtp.mailfrom=0sec.ai; dkim=temperror (0-bit key) header.d=0sec.ai header.i=@0sec.ai header.b=dnJ3cZrM; arc=none smtp.client-ip=209.85.128.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=0sec.ai Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=0sec.ai Authentication-Results: smtp.subspace.kernel.org; dkim=temperror (0-bit key) header.d=0sec.ai header.i=@0sec.ai header.b="dnJ3cZrM" Received: by mail-wm1-f51.google.com with SMTP id 5b1f17b1804b1-493bc8fda98so9872025e9.0 for ; Sat, 11 Jul 2026 01:03:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=0sec.ai; s=google; t=1783757033; x=1784361833; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=HKkmmaE0aEFKxqkQuCsGPJUCathBrKzfhSwzLLCu+L0=; b=dnJ3cZrMCfUxwAA0AUveedMgxugJVSx4g+CaJfdzEOKelok+f7f0PwaBnGj5jqIIQo OdbJIu2QgqixLWSAYeju4svEsWeSHXC1oCgIC7a87fsyFsCrJBfsnEfyamCgYGOkEDqV 4XSthPfzNwX8sgCCmBYNUJgWge5ZtLHqgLg0RHHiLChdt4lLoN38iUnQshGd+y7+3Rzl nJYasqwoqlhs7Bz9YuiRwbultSZpAauQceSvKyZYKlNOXb/jHwfPBW2Hpjc7qdlb69bQ X7vRgk3PRJLDZujIhFSdHiXqYsXNs52WpjJzYdz4VcD1c1NaKRsOMTcTtooxbhx02/PY 5GWQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783757033; x=1784361833; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=HKkmmaE0aEFKxqkQuCsGPJUCathBrKzfhSwzLLCu+L0=; b=Lgst0C6U7MtqWMfJVUsKQnZZV5cW8102sSWbejKYdwfV9DU5MtKiOVI99lOtOrHmuO tsvJHM8YqRvRaGuwXvp+cbNRI4jyyu7X3kwwHks9WVJ62QjP1Kbnq5ZRnzgJwdouc/Pz eGeXlZz7Nd1BPbvenmLS27KtY/ljt78uqDk6QfsBT09ZQrXNSfH31XSvhJdytlRtmxL/ JNT+Rqyz/TuRxOHdeCZbT3ZwXWuLSG5SczUbS2L91DZVYxzyj5sJ37VyGolvLHVR1I70 OCaHubj0XtbYW40/EGbLQSf4uG/hJYH2kGZjZ7rlkAyV2VGar3cVghb5gAVF5BbGR3Ge 3PXg== X-Forwarded-Encrypted: i=1; AHgh+RrMbIyKw/9KUrVukZJ2Kau9b2CCcGogW7zAzLOchQj4KAa3kfru5KGP3Rdvj3G2ZFScfA9lqAGpCl6jcRs=@vger.kernel.org X-Gm-Message-State: AOJu0YwGAeXtIkq+NDcAhmnFxVlzH7+XWv36IMHUs6TtuCTSRWtUvx1m tFUO18Fg+8f21pCrzGUDqc3if+5cxb9FCfG5fm5WDhbenU3HqLWTJq7Ibt2Ic3RjzQq1 X-Gm-Gg: AfdE7cm/RNHCuvpRkk/6Z2Mq/jyDlEm/n5y+8uOLqOEFlpbrnAon7lLscCz4UJrbMk8 Qu7+h97xQHdSo9nlCxdpt9jG6jKQBrEMWzt2kDZG+NNjNDGRdoYluPxaDeaQnpmv97TkHBdzEpk PLBuDsj8D0Gqs7dqzcW5FfGF+xPHhUHvCY9wcCSd5zbxpWxZraTjWgqRsSxPAe2PFxf7q/kaDjk Ae6SBwnb1LbiistmzavXe/WDvWLgI4Uxksz27MYv5dzS7Ygs/c11pHBtksXeTr1zzd5RFCwDbwW 3fw9wEIN37Wra6LnYqkFFZIQMjMbEzr7z12TFobIRuUVVF8SrpOJuJoeTN6g8qgGqVj1cwBoFWL f9UeelPNzW7LVRpZDunG9k09AJjhsAkrQ6Zcoe5e9POoq7gZK3V+TPFJ26Oi9qkVm6Ib87KEd/n u/CL+0p6zs3s2Gx/EqQifuXC7wTpylILIIXo97PevD6PgEsKL3Qz0Bo1wFv1JNc8oNXyYjU9fmC RHIZYQyF04s9YvYvSvpE78eJmizUvn80Gw= X-Received: by 2002:a05:600d:8444:10b0:493:e46a:ab with SMTP id 5b1f17b1804b1-493f8837638mr12182095e9.34.1783757033565; Sat, 11 Jul 2026 01:03:53 -0700 (PDT) Received: from PeakBook-Mini.tail8e484.ts.net ([178.197.218.188]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-493f2dad65fsm77881195e9.1.2026.07.11.01.03.52 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Sat, 11 Jul 2026 01:03:52 -0700 (PDT) From: Doruk Tan Ozturk To: jikos@kernel.org, bentiss@kernel.org Cc: spbnick@gmail.com, linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, stable@vger.kernel.org, Doruk Tan Ozturk Subject: [PATCH v2] HID: uclogic: fix UAF on inrange_timer at teardown and probe error Date: Sat, 11 Jul 2026 10:03:50 +0200 Message-ID: <20260711080350.81108-1-doruk@0sec.ai> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260711073003.71012-1-doruk@0sec.ai> References: <20260711073003.71012-1-doruk@0sec.ai> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" uclogic_probe() arms a per-device timer whose callback uclogic_inrange_timeout() dereferences drvdata->pen_input, and uclogic_raw_event_pen() re-arms it with a 100 ms timeout on every in-range pen report. uclogic_remove() drained the timer with timer_delete_sync() before hid_hw_stop(). timer_delete_sync() does not block re-arming: a pen report delivered before hid_hw_stop() kills the URBs can re-arm the timer after it was drained. hid_hw_stop() then frees the hidinput pen_input (via hidinput_disconnect() -> input_unregister_device()), and the pending timer fires on freed memory. Use timer_shutdown_sync() instead, still before hid_hw_stop(). It drains the callback while pen_input is still valid and permanently blocks re-arming, so an in-flight raw_event cannot revive the timer; hid_hw_stop() then frees pen_input with the timer already dead. The probe error path had the same exposure: if hid_hw_start() started I/O and then failed, raw_event may have armed the timer, which would fire on the devm-freed drvdata after probe returns. Shut the timer down there too. Unlike letsketch, whose input devices are devm-allocated and outlive hid_hw_stop(), uclogic's pen_input is freed inside hid_hw_stop(), so the timer must be shut down before it rather than after. Found by 0sec (https://0sec.ai) using automated source analysis; not runtime-reproduced. Fixes: 01309e29eb95 ("HID: uclogic: Support in-range reporting emulation") Cc: stable@vger.kernel.org Assisted-by: 0sec:claude-opus-4-8 Signed-off-by: Doruk Tan Ozturk --- v2: - Shut the timer down *before* hid_hw_stop() rather than after. v1 mirrored the letsketch ordering (hid_hw_stop() first), but uclogic's pen_input is the hidinput device freed inside hid_hw_stop(), not a devm device that outlives it as in letsketch. A timer armed just before the URBs are killed could still fire on the freed pen_input in the window before timer_shutdown_sync() drained it. Running timer_shutdown_sync() before hid_hw_stop() drains the callback while pen_input is still valid and blocks re-arming, closing that window. - Also shut the timer down on the probe error path. drivers/hid/hid-uclogic-core.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c index b73f09d26688..d74f98efa879 100644 --- a/drivers/hid/hid-uclogic-core.c +++ b/drivers/hid/hid-uclogic-core.c @@ -267,6 +267,13 @@ static int uclogic_probe(struct hid_device *hdev, /* Assume "remove" might not be called if "probe" failed */ if (params_initialized) uclogic_params_cleanup(&drvdata->params); + /* + * If hid_hw_start() started I/O and then failed, raw_event may have + * armed the timer; shut it down so it cannot fire on the devm-freed + * drvdata after probe returns. + */ + if (drvdata) + timer_shutdown_sync(&drvdata->inrange_timer); return rc; } =20 @@ -548,7 +555,15 @@ static void uclogic_remove(struct hid_device *hdev) { struct uclogic_drvdata *drvdata =3D hid_get_drvdata(hdev); =20 - timer_delete_sync(&drvdata->inrange_timer); + /* + * timer_delete_sync() does not prevent re-arming, so a pen report + * delivered before hid_hw_stop() kills the URBs could re-arm the + * timer; hid_hw_stop() then frees the hidinput pen_input and the + * pending timer fires on freed memory. timer_shutdown_sync() drains + * the callback while pen_input is still valid and permanently blocks + * re-arming, so an in-flight raw_event cannot revive it. + */ + timer_shutdown_sync(&drvdata->inrange_timer); hid_hw_stop(hdev); kfree(drvdata->desc_ptr); uclogic_params_cleanup(&drvdata->params); --=20 2.43.0