From 970ec26bb0efabe7d04c95cb8d54546590601760 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Wed, 12 Aug 2026 14:01:58 +0200 Subject: [PATCH] Don't let a usbfs claim count as a kernel driver (#6744) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The vendor-ID guess rejects any device with a driver bound, on the reasoning that libfprint drives readers from userspace so a real one sits there unbound. But libusb claims interfaces through a synthetic usbfs driver, so the reader binds one for as long as fprintd holds the claim — which is exactly while it is being enrolled or verified against. Readers that name themselves take the product-string branch and never reach this, so the exposure is the ones that don't: Goodix 27c6:6594 reports "Goodix USB2.0 MISC", matches on vendor ID alone, and drops out of detection mid-authentication. The menu entry disappears and the first-run invitation stops firing while the reader is in use. Ignore a driver link that resolves to usbfs, and keep rejecting the real ones — usbio-bridge, usbhid, uvcvideo — including on a device that has both. Co-authored-by: Claude Opus 5 (1M context) --- bin/omarchy-hw-fingerprint | 10 ++++++++-- test/shell.d/hw-fingerprint-test.sh | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/bin/omarchy-hw-fingerprint b/bin/omarchy-hw-fingerprint index 6f4b407b..cdaf040a 100755 --- a/bin/omarchy-hw-fingerprint +++ b/bin/omarchy-hw-fingerprint @@ -18,9 +18,15 @@ usb_devices_path="${OMARCHY_USB_DEVICES_PATH:-/sys/bus/usb/devices}" # — all bind one. Only the vendor-ID guess needs this; a device that names # itself a fingerprint reader is trusted outright. has_kernel_driver() { - local intf + local intf driver for intf in "$1"/*:*; do - [[ -e $intf/driver ]] && return 0 + [[ -e $intf/driver ]] || continue + # usbfs is the exception: libusb claims an interface through it, so a reader + # fprintd is enrolling or verifying against binds a driver for as long as it + # holds the claim. That is userspace driving the device — what a reader is + # supposed to look like — so it must not read as a kernel driver here. + driver=$(readlink -f "$intf/driver") + [[ ${driver##*/} == "usbfs" ]] || return 0 done return 1 } diff --git a/test/shell.d/hw-fingerprint-test.sh b/test/shell.d/hw-fingerprint-test.sh index 78525c86..6ae30a25 100755 --- a/test/shell.d/hw-fingerprint-test.sh +++ b/test/shell.d/hw-fingerprint-test.sh @@ -87,5 +87,19 @@ write_usb_devices '27c6:1234' bind_driver '1-0/1-0:1.0' uvcvideo assert_rejects "a vendor guess bound to a kernel driver is rejected" +write_usb_devices '27c6:1234' +bind_driver '1-0/1-0:1.0' usbfs +assert_detects "a vendor guess claimed through usbfs is still detected" + +write_usb_devices '27c6:1234' +bind_driver '1-0/1-0:1.0' usbfs +bind_driver '1-0/1-0:1.1' uvcvideo +assert_rejects "a real driver alongside a usbfs claim is still rejected" + +# The product-name branch is trusted outright, whatever is bound to it. +write_usb_devices '27c6:1234:Goodix Fingerprint USB Device' +bind_driver '1-0/1-0:1.0' uvcvideo +assert_detects "a self-named reader is detected with a driver bound" + write_usb_devices '1234:5678:Generic USB Device' assert_rejects "a machine with no matching USB devices detects nothing"