Files
omarchycn/test/shell.d/hw-fingerprint-test.sh
970ec26bb0 Don't let a usbfs claim count as a kernel driver (#6744)
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) <noreply@anthropic.com>
2026-08-12 14:01:58 +02:00

106 lines
3.2 KiB
Bash
Executable File

#!/bin/bash
set -euo pipefail
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
tmp_dir=$(mktemp -d)
trap 'rm -rf "$tmp_dir"' EXIT
write_usb_devices() {
rm -rf "$tmp_dir/devices"
mkdir -p "$tmp_dir/devices"
local index=0
local spec
for spec in "$@"; do
local vendor=${spec%%:*}
local remainder=${spec#*:}
local product_id=${remainder%%:*}
# A spec with no third field describes a device with no product
# descriptor. Without this guard ${remainder#*:} would return the product
# id unchanged and quietly write it out as the product string.
local product=""
if [[ $remainder == *:* ]]; then
product=${remainder#*:}
fi
local dev="$tmp_dir/devices/1-$index"
mkdir -p "$dev"
printf '%s\n' "$vendor" >"$dev/idVendor"
printf '%s\n' "$product_id" >"$dev/idProduct"
[[ -n $product ]] && printf '%s\n' "$product" >"$dev/product"
index=$((index + 1))
done
}
hw_fingerprint() {
OMARCHY_USB_DEVICES_PATH="$tmp_dir/devices" "$ROOT/bin/omarchy-hw-fingerprint"
}
assert_detects() {
local description="$1"
hw_fingerprint || fail "$description"
pass "$description"
}
assert_rejects() {
local description="$1"
if hw_fingerprint; then
fail "$description"
fi
pass "$description"
}
write_usb_devices '10a5:a305:FPC L:0000 FW:1425046'
assert_detects "an FPC reader is detected by its product string"
write_usb_devices '10a5:1234:Generic USB Device'
assert_rejects "a generic 10a5 USB device is not detected"
write_usb_devices '10a5:9800:FPC Sensor Controller L:0002 FW:25.26.23.14'
assert_detects "an FPC reader is detected by its sensor-controller string"
# Pins the match to a prefix. FPC abbreviates unrelated things too, and this
# branch is trusted with no kernel-driver check, so the token is not enough.
write_usb_devices '0bda:5842:USB2.0 FPC Camera'
assert_rejects "an FPC token mid-string is not detected"
write_usb_devices '1234:5678:Goodix Fingerprint USB Device'
assert_detects "a reader is detected by an existing product-name match"
write_usb_devices '27c6:1234'
assert_detects "a reader is detected by an existing vendor match"
bind_driver() {
local dev="$1" driver="$2"
# sysfs links the interface at a driver directory, and the detector's [[ -e ]]
# follows the link, so the target has to exist for this to model anything.
mkdir -p "$tmp_dir/drivers/$driver" "$tmp_dir/devices/$dev"
ln -sf "$tmp_dir/drivers/$driver" "$tmp_dir/devices/$dev/driver"
}
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"