Hydrogell/goodix-27c6-55a4-fingerprint-linux

GitHub: Hydrogell/goodix-27c6-55a4-fingerprint-linux

为常见于联想多款笔记本上的 Goodix 55a4 指纹传感器提供可在 Linux 上正常工作的 libfprint 驱动补丁及一键安装方案。

Stars: 0 | Forks: 0

# Linux 上的 Goodix 27c6:55a4 指纹传感器 一个可用于 **Goodix 55a4** 指纹传感器的正常工作的 libfprint 驱动,该传感器常见于 Lenovo ThinkBook 15 G2 ITL 及该代的其他机器上。 这款传感器目前没有任何可用的开源驱动:无论是 AUR 软件包 `libfprint-goodixtls-55x4` 还是 Fedora COPR 的 `d-k-bo/libfprint-goodixtls` 都声明支持 55b4,并表示“55a4 会在以后添加”。本仓库就是那个“以后”。 它是基于 [TheWeirdDev/libfprint][fork] 的 `55b4-experimental` 分支制作的补丁,并附带了用于构建、安装和测试它的脚本。 ## 这适用于我吗? 运行以下命令: ``` lsusb | grep 27c6 ``` 如果你看到 **`27c6:55a4`**,那么就适用。(`ID 27c6:55a4 Shenzhen Goodix Technology Co.,Ltd. Goodix FingerPrint Device`) 已知搭载此传感器的机器(数据来源于 [linux-hardware.org][lhw] 及相关报告): - Lenovo **ThinkBook** 13 / 14 / 15 — 包括 14-IIL (20SL)、14s IWL 以及作为本驱动开发机型的 15 G2 ITL (20VE) - Lenovo **ThinkPad** E14 / E15 - Lenovo **IdeaPad 3 14** - Lenovo **ZHAOYANG K4e** linux-hardware.org 列出了搭载该设备的 **783 台机器**,并且每一台都被记录为*失败* — 没有可用的驱动。这正是本仓库所要填补的空白。 Linux 发行版影响不大:这是在 Fedora 上构建的,但该传感器在 Ubuntu、Mint、Manjaro、Pop!_OS、Zorin 和 Kali 上都会报告相同的故障。如果你是因为 Goodix 指纹读取器在 Linux 下无法工作,并且 `fprintd-enroll` 提示*"No devices available"*(没有可用设备),或者你的设备从未出现在 GNOME/KDE 设置中而来到这里 — 那么你来对地方了。 **相关但不同的设备:** 如果 `lsusb` 显示 `27c6:55b4`,请改用 [libfprint-goodixtls-55x4][aur];如果显示的是其他 `27c6:5xxx` 设备,请查看 [goodix-fp-dump][gfd] 以确认是否支持你的型号。`goodixmoc` 系列传感器(芯片端匹配)已由上游 libfprint 直接支持,不需要使用本项目。 ## 状态 录入和验证可通过自带的 `fprintd` 正常工作,包括 PAM — 屏幕解锁、登录和 `sudo`。以下为在一台机器上,由单人按下真实手指测得的数据: | | 结果 | |---|---| | 正确接受,刻意偏移手指 | 87.5 % (7/8) | | 正确接受,旋转高达 90° | 87.5 % (7/8) | | 正确接受,交叉手指测试 | 100 % (6/6) | | **错误接受,38 次冒充按压** | **0** | 冒充测试的数据包含了:用未录入的手指与每一个已录入的指纹进行比对的 14 次按压,与单个指纹比对的 12 次按压,以及与第二个已录入手指进行的 12 次交叉手指试验 — 这是最难的情况,因为同一只手的两根手指比两个人的手指更像。 请将其视为“没有开大坑”,而不是确切的错误接受率:0/38 仅在 95% 的置信度下将其限制在约 8% 左右。真实的数值需要进行数百次试验,这是靠手工无法达到的。 ## 安装 本项目是在 Fedora 上开发和测试的。其他发行版理论上也可以运行,但尚未有人尝试过。 首先安装构建依赖: ``` sudo dnf install meson ninja-build gcc gcc-c++ libgusb-devel nss-devel \ openssl-devel cairo-devel glib2-devel opencv-devel \ gobject-introspection-devel libgudev-devel pixman-devel doctest-devel cmake ``` 然后执行: ``` git clone https://github.com/Hydrogell/goodix-27c6-55a4-fingerprint-linux cd goodix-27c6-55a4-fingerprint-linux ./install.sh ``` `install.sh` 会在一个临时目录中进行构建、安装,然后**删除构建树**。它只会在安装步骤请求一次你的密码(以获取权限)。之后你的主目录中不会留下任何内容,你也可以直接删除克隆下来的代码仓库 — 运行该驱动并不需要保留它,只有在卸载时才会用到。 接着录入指纹: ``` fprintd-enroll # 16 touches; vary the finger position between them fprintd-verify ``` 操作到此结束。本文件的其余部分适用于想了解它对系统做了什么,或者想要参与驱动开发的人。 ### 开发与调试驱动 如果你想阅读代码、重新构建或运行准确度测试工具,请使用开发者模式路径。它会保留构建树 — 包含两个代码检出和一个 Python virtualenv,在 `work/` 下约占 300 MB — 方便你进行编辑和重新构建: ``` ./setup.sh # keeps ./work/ sudo bash scripts/install-system.sh # installs whatever is in ./work/ ``` `scripts/fp-notify.sh` 和 `scripts/fp-stress.sh` 封装了录入和验证流程,并配带有桌面通知,会准确告诉你何时按压以及结果如何,这比盯着终端看要省力得多。 `fp-stress.sh` 会运行交叉手指矩阵测试,因此需要录入**两根**手指,否则将拒绝启动: ``` fprintd-enroll -f right-index-finger fprintd-enroll -f right-thumb scripts/fp-stress.sh # 3 rounds -> 12 presses ``` 关于如何在修改后重新生成补丁,请参阅 [`CONTRIBUTING.md`](CONTRIBUTING.md);有关协议说明和完整的技术解析,请参阅 [`docs/`](docs/)。 ### 安装脚本的具体行为 它**不会**替换或降级你发行版自带的 libfprint。打过补丁的构建版本会被安装到 `/opt/libfprint-goodix`,并且一个 systemd drop-in 配置*仅*针对 `fprintd` 指向该版本。系统上的其他所有程序仍会继续使用发行版自带的库。 它还会配置传感器密钥(见下文),检查你的指纹模板是否存储在加密文件系统上,并报告 SELinux 是否处于强制模式。 如果是在强制模式的 SELinux 系统上,它会加载一个仅包含一条规则的策略模块,即 [`scripts/goodix_fprintd.te`](scripts/goodix_fprintd.te)。OpenCV 会引入 Intel TBB,其内存分配器会去探测 `/proc/sys/vm/nr_hugepages`;而 fprintd 的域可能无权读取该路径,因此 Fedora 会在每次 fprintd 启动时引发 SELinux 警报。这条规则是一个 `dontaudit` — 它不授予 fprintd 任何访问权限,仅仅是阻止拒绝访问被记录到日志中。如果缺少 `checkmodule`/`semodule`,则会跳过此步骤。 它会全局启用指纹身份验证 — 在 Fedora 上对应为 `authselect enable-feature with-fingerprint` — 这样 GDM、`login` 和 `sudo` 随后都会接受指纹验证。如果你只想要录入和测试,请在运行安装程序之前将这一步注释掉。 `sudo bash scripts/uninstall-system.sh` 会移除该库、systemd drop-in 配置和策略模块。但有件事它不会撤销:PAM 仍会继续接受指纹验证 — 你可以通过 `authselect disable-feature with-fingerprint` 将其关闭;写入传感器的密钥是永久性的(它与 Windows 原厂驱动使用的密钥槽不同 — 请参阅 [传感器密钥](#the-sensor-key));并且你录入的任何指纹都会保留在 `/var/lib/fprint` 中。你可以使用 `fprintd-delete $USER` 来删除它们。 ## 安全性 — 部署前必读 默认情况容易引人误解,因此我们直白地说明: **USB 通道是加密的,但并不保密。** 它运行 TLS 1.2 (`PSK-AES128-CBC-SHA256`),因此每次会话的传输字节都不同 — 但预共享密钥是 32 个零字节,这是通过写入一个已在 [goodix-fp-dump][gfd] 中公开多年的固定 blob 强制设置的。任何了解该协议的人都可以将其解密。我们无法使用自己的密钥:密钥是作为由供应商白盒加密包装的 96 字节 blob 写入的,目前只有全零密钥是公开的。每一个开源的 Goodix 驱动都面临同样的处境。 **传感器在主机端进行匹配。** 它没有片上匹配器,因此原始图像会经过总线传输并在普通内存中处理。任何软件都无法改变这一点。目前存在片上匹配的传感器,并且 libfprint 支持其中的几种(`goodixmoc`、`elanmoc`、`fpcmoc`、`synaptics`)— 在这些传感器中,指纹图像永远不会离开芯片裸片。 **模板以未加密形式存储。** `fprintd` 会将它们作为普通文件写入 `/var/lib/fprint`;这是一个长期存在的上游遗留问题,而不是本驱动引入的。它们仅限 root 访问,但在未加密的磁盘上,任何能够拆卸硬盘的人都可以读取它们,并且凭借一个模板就足以重建出与原始手指极其相似的图像。请使用全盘加密并保持 LSM(Linux 安全模块)处于强制模式 — 上游对此问题的官方回应就是“使用 SELinux 或 AppArmor”。 **合理的建议:** 将指纹视为一种便利手段,而不是安全边界。请将磁盘、账户密码以及任何有价值的东西交由真正的密钥加密保护。 ## 传感器密钥 驱动程序使用全零密钥进行 TLS-PSK 通信,只有当公开的“白盒” blob 被写入传感器后,它才会接受该密钥。该 blob 并非特定于设备的,也不是从任何人的硬件中提取的 — 它内置于 goodix-fp-dump 中。写入它只是一次性操作,安装程序会为你完成(`scripts/provision_psk.py`,具有幂等性)。 在双系统启动的情况下,为了严谨地说明已知信息,因为这是你必须信任的部分: 这些存储槽是相互独立的,这一半是代码层面的事实,而非单纯的观察。Windows 将其密钥材料保存在 `0xbb010002` 中;而此处的任何代码唯一写入的存储槽是 `0xbb010003` — 即 goodix-fp-dump 的 `write_psk()`(在 `driver_55x4.py` 中对应为 `preset_psk_write(0xbb010003, PSK_WHITE_BOX)`),这也就是 `provision_psk.py` 所调用的内容。C 语言驱动程序根本不会写入任何密钥:它只会读取 `0xbb020007` 中的哈希值,如果不正确则拒绝激活。这里的任何代码路径都不会涉及 `0xbb010002`,因此配置操作根本不会触碰 Windows 保存在那里的内容。 至于 Windows 之后会做什么,我们只观察到过一次,并未进行严密测量。将传感器直通给 Windows 虚拟机后,在本设备已被配置的情况下,一个 Windows 会话录入了一个指纹,其 USB 捕获记录显示供应商驱动程序将其自带的 324 字节 DPAPI blob 写入了 `0xbb010002` — 它会自行配置该存储槽。之后进行检查时发现,Linux 端的白盒密钥仍然有效。这仅仅是基于一台机器上的一次会话观察到的结果,而且设备直通并不等同于真正的双系统启动,因此请将“双方共存”视为一种基于单次观察的期望,而不是经过测试的结论。如果你在安装此驱动后,发现 Windows 的指纹登录出现异常,在 Windows 下重新录入指纹应该就能恢复;无论结果如何,请提交一个 Issue,因为这意味着本节内容需要更正。 ## 究竟哪里出了问题 原来的驱动程序并不是简单的“不存在” — 55b4 的驱动程序曾能在该传感器上运行,但三次按压中大约只能识别成功一次。从那种状态走到今天这一步,意味着我们找到了八个独立的缺陷。其中几个有趣的问题不仅限于本设备,具有广泛的代表性: - **手指检测阈值是因设备而异的,而不是固定常量。** 设备会在 `FDT_MODE` 回复中报告自身测量到的各个区域的基础值,而供应商驱动会传回 `base >> 1`。原来的驱动程序硬编码了 55b4 的数值,偏差了约 10 倍,因此设备端的手指检测在 55a4 上根本无法触发。 - **SIGFM 匹配器中存在三个真实的 bug**,这会影响所有使用它的设备: 一个比较器被简化为仅对 `y` 进行排序,从而悄无声息地丢弃了大约一半的匹配;一个角度一致性测试在角度上使用了*相对*差值,在正好旋转四分之一圈(90°)时会退化为 `0/0`,因此完美一致的 90° 旋转总是会被拒绝;以及 `asin`/`acos` 的定义域溢出在零旋转的情况下恰好返回了 `NaN`。 - **背景帧是在手指可能还停留在面板上时捕获的**,这不仅会在手指抬起时产生幻影触摸,还会悄悄破坏每一帧图像,因为图像帧的计算方式为 `|frame − background|`。 - **状态指示灯是可以通过命令控制的**,即命令 `0xae` — 也就是社区协议说明中称为 `QUERY_MCU_STATE` 的那个命令,这就是为什么之前没人发现它的原因。 [`docs/TECHNICAL.md`](docs/TECHNICAL.md) 提供了包含测量数据的完整解析[`docs/PROTOCOL.md`](docs/PROTOCOL.md) 则单独提供了协议发现,供任何正在研究该系列其他传感器的人参考。 ## 限制与注意事项 - 仅在**一台** 55a4 设备上、由单人进行了测试。请将这些数据视为参考指标。 - FDT 阈值学习通过设备 ID 故意**限制在 55a4 上**:55b4 随机附带了三种不同的阈值表,如果将学习到的一套阈值应用在上面,会使其手指抬起阈值提高约三分之一,这会导致每次捕获后程序卡死。如果你使用的是 55b4 并想进行尝试,相关标志位是 `goodix55x4.h` 中的 `GOODIX_55X4_FLAG_LEARN_FDT`。 - 触摸阈值是仅根据一根手指校准的。如果你发现捕获不可靠,可以通过环境变量覆盖它:`GOODIX55X4_TOUCH_DIFF=200`。 - 所基于的 fork 分支属于 libfprint 1.94.6 时代。匹配器的修复值得单独贡献给上游;而驱动程序本身目前没有上游归属,因为 freedesktop 的 libfprint 根本没有 `goodixtls` 相关的代码树。 ### 协议行为是如何确定的 **未包含任何供应商代码,也绝未抄袭。** `patches/` 中的所有内容都是完全基于 libfprint 自身的 API 从头编写的。 共有三个来源,且全部基于作者本人的硬件测试: 1. **USB 流量**,使用 `usbmon` 在原厂 Windows 驱动程序于虚拟机中驱动传感器时捕获。命令序列、时序和阈值数值均来源于此。 2. **设备本身** — 即设备在自己的回复中报告的值,例如作为 `base >> 1` 规则推导基础的 FDT 基准线。 3. **供应商的 Windows 驱动程序,出于互操作性目的进行了分析。** `docs/PROTOCOL.md` 中的某些细节是无法从数据流中获取的 — 比如字面上的分支字符串(`"image base not valid, wait fdt up"`)以及帧选择规则。这些是为了弄清楚传感器为何会表现出当前行为,而从出厂的驱动二进制文件中逆向分析出来的,随后进行了独立重新实现。 这第三点就是所谓的互操作性逆向工程:研究你必须与之通信的接口,以便编写出能与其交互的代码。欧盟(Directive 2009/24/EC, Art. 6)和美国(17 U.S.C. §1201(f))的法律都明确允许出于此目的进行此类操作,而且这也是为无文档硬件编写所有开源驱动的通用方法。这里产出的结果是对*行为*的描述,而不是对*表达(原始代码)*的复制 — 没有借用任何供应商的代码、结构或数据。 先前的开源工作已在上方注明出处;对于 [goodix-fp-dump][gfd] 或 55b4 打包者已经发布过的事实,本仓库是在其基础上进行构建的,而非重新发现它们。
标签:libfprint, Linux驱动, 指纹传感器, 生物识别, 硬件兼容, 系统驱动, 逆向工具, 预握手