KDE released Plasma 6 a few weeks ago and it’s extremely awesome and also quite buggy. One of the most annoying bugs has been that the lockscreen is sometimes missing the fingerprint login option after resuming from sleep, so I have to type in my password instead. Of course there’s the big question about the security of fingerprint login, but I think it’s more likely for someone to shoulder surf me rather than knock me unconscious and tap my finger to the sensor. Also, fingerprint login is more convenient. Anyways, I’m just going to ignore that question and focus on this bug instead.
While debugging this, the first main obstacle I ran into is that the KDE’s PAM configuration doesn’t reset pam_faillock
after a successful fingerprint login, which has been reported here. Basically, whenever you log in with your fingerprint, it gets counted as a failed login anyways and after three tries, you get locked out! The fix is also included in that bug report and just requires adding this to the bottom of the auth
section in /etc/pam.d/kde-fingerprint
:
auth required pam_faillock.so authsucc
Once I got that out of the way, I enabled debug=on
for pam_fprintd
(a PAM module to use the fingerprint reader for authentication) to see debug messages for it in the system journal. After triggering the bug and checking the journal with journalctl -xe
, I found a suspicious line:
Mar 19 20:27:53 ThinkPad-X1-Yoga-Gen-6 kscreenlocker_greet[14561]: pam_fprintd(kde-fingerprint:auth): Using device (null) (out of 0 devices)
Whoa! There’s the problem! pam_fprintd
is not detecting my laptop fingerprint reader at all. Furthermore, this line is located very early in the wake-up process, when some USB devices haven’t been initialized yet!
lsusb
says that my fingerprint reader has ID 06cb:00fc
, and sure enough, the lines for that are located after the pam_fprintd
line:
Mar 19 20:27:53 ThinkPad-X1-Yoga-Gen-6 kernel: usb 3-3: new full-speed USB device number 117 using xhci_hcd
Mar 19 20:27:53 ThinkPad-X1-Yoga-Gen-6 kernel: usb 3-3: New USB device found, idVendor=06cb, idProduct=00fc, bcdDevice= 0.00
Mar 19 20:27:53 ThinkPad-X1-Yoga-Gen-6 kernel: usb 3-3: New USB device strings: Mfr=0, Product=0, SerialNumber=1
Mar 19 20:27:53 ThinkPad-X1-Yoga-Gen-6 kernel: usb 3-3: SerialNumber: f88de24e63f0
This is progress. pam_fprintd
starts the systemd service fprintd.service
, so I just need to make this service start after the fingerprint device is initialized. Fortunately, this is doable with systemd but a bit complicated. First, create a udev rule for the device in /etc/udev/rules.d/69-fingerprint.rules
:
ATTRS{idVendor}=="06cb", ATTRS{idProduct}=="00fc", SYMLINK="fingerprint", TAG+="systemd"
Next, reload udev rules with sudo udevadm control --reload-rules && sudo udevadm trigger
. Now create an override file for fprintd.service
using sudo systemctl edit fprintd.service
and paste in this stuff:
[Unit]
After=suspend.target dev-fingerprint.device
Requires=dev-fingerprint.device
The suspend.target
is important because the dev-fingerprint.device
seems to initially be active right after the wake-up starts, but then gets deactivated and reactivated during wake-up. Thus, we have to wait until after the wake-up finishes, then wait for dev-fingerprint.device
to be active.
So, to recap, the bug actually has isn’t KDE Plasma’s fault. I guess it’s an fprintd
problem since maybe it should wait a bit until the USB devices are all initialized? I’m not sure. The only reason I ran into this bug is because previously, Plasma required pressing enter first to show the fingerprint login prompt, but in Plasma 6 is immediately shows the fingerprint login prompt. This causes a race condition with USB device initialization, so the bug doesn’t always happen if the USB devices win the race.
Another potential problem is that fprintd
waits around 30 seconds after a successful login before quitting, so sleeping and waking up and sleeping and waking up can cause the bug to reappear during the second wake-up, but I don’t think I’d ever run into this corner case except while debugging this bug. When debugging, I had to manually run sudo killall fprintd
between sleep-wake up tests.
It turns out the 30 second timeout is hardcoded in the source code, so I changed it to 1 and recompiled fprintd, which fixed this problem. (Sidenote: the fprintd README says “Might eat your kangaroo”) I might try contributing this fix to fprintd, but maybe they have a reason for 30 as the default. Also, fprintd doesn’t seem actively maintained anymore.
Maybe there’s a better way to solve this. If you know of a better solution, please let me know! It’s definitely a bit upsetting that I need to mess with PAM config files, udev rules, systemd override files, and recompile fprintd to get my fingerprint reader to work properly, but I guess that’s the struggle of Linux sometimes. I wish Lenovo could provide better support for Linux on my laptop model, since they do sell a preinstalled Ubuntu version of that model.
Edit: I found a slightly better solution. Linux has an obscure feature called USB persist that reuses the data structures for a USB device instead of rebuilding it after a suspend. I tried enabling this for my fingerprint reader and it works! Now my reader doesn’t even need to be initialized during the wake-up process, which avoids the problem from earlier. To enable persist, I changed the udev rule to this:
ACTION=="add", SUBSYSTEM=="usb", DRIVERS=="usb", ATTRS{idVendor}=="06cb", ATTRS{idProduct}=="00fc", ATTR{power/persist}="1", RUN="/usr/bin/chmod 444 %S%p/../power/persist"
I noticed that this kept on getting disabled for some reason after each wake-up, so I changed the file to have permissions 444 to stop that. With this solution, I no longer need the systemd override anymore, but still need to recompile fprintd which is annoying.
Edit 2: I was trying to investigate why I still needed to recompile fprintd. The unpatched version gives this error if I sleep then resume while fprintd
is still running in the background:
Mar 21 19:27:44 ThinkPad-X1-Yoga-Gen-6 kscreenlocker_greet[16753]: pam_fprintd(kde-fingerprint:auth): debug on
Mar 21 19:27:44 ThinkPad-X1-Yoga-Gen-6 kscreenlocker_greet[16753]: pam_fprintd(kde-fingerprint:auth): debug on
Mar 21 19:27:44 ThinkPad-X1-Yoga-Gen-6 kscreenlocker_greet[16753]: pam_fprintd(kde-fingerprint:auth): /net/reactivated/Fprint/Device/0 prints registered: 2
Mar 21 19:27:44 ThinkPad-X1-Yoga-Gen-6 kscreenlocker_greet[16753]: pam_fprintd(kde-fingerprint:auth): Using device /net/reactivated/Fprint/Device/0 (out of 1 devices)
Mar 21 19:27:44 ThinkPad-X1-Yoga-Gen-6 kscreenlocker_greet[16753]: pam_fprintd(kde-fingerprint:auth): failed to claim device Open failed with error: The device is still busy with another operation, please try again later.
Also, it seems like fprintd is the one trying to disable USB persist for some reason. It’s also possible that maybe my fingerprint reader just works perfectly with S2Idle sleep instead of S3, but switching to a battery-draining sleep state seems like a bad tradeoff. If anyone has further insights into these problems, I’d love to hear it!
Edit 3: I finally found a nice solution to all my problems! No more udev rules, no more compiling fprintd. Just make a systemd service file at /etc/systemd/system/fingerprint.service
containing this:
[Unit]
Description=Kill fprintd and enable USB persist before sleep
Before=sleep.target
[Service]
ExecStart=/usr/bin/sh -c "killall fprintd; echo 1 > /sys/bus/usb/devices/3-3/power/persist"
[Install]
WantedBy=sleep.target
Now run sudo systemctl enable fingerprint
and voilà, all problems fixed! Awesome!
It might seem like I pulled that systemd service out of a magic hat, but the basic idea is to make sure fprintd isn’t running during the sleep and to enable USB persist. I originally tried using an obscure systemd feature called systemd-sleep, but it wouldn’t work unless I placed the script in /usr/lib/systemd/system-sleep
, not /etc/systemd/system-sleep
. I saw someone online suggest simply writing a systemd service instead. Anyways, I hope you enjoyed this tour through a bunch of obscure Linux and systemd features. Well, I didn’t really enjoy it honestly. The documentation was all bad and searching for stuff like “run systemd service before sleep” gets barely any relevant results.
Alright, so if you managed to reach the end of this post and understood everything, congratulations! You deserve a bowl of Biángbiáng noodles!