Closed EvilBit closed 3 years ago
Thank you for your detailed report! Could you test the following approach, please, which works at least on my machine?
/usr/lib/systemd/system/tpm2-totp.service
:
[Unit]
Description=Display a TOTP during boot
Requires=systemd-vconsole-setup.service dev-tpm0.device
After=systemd-vconsole-setup.service dev-tpm0.device
Conflicts=multi-user.target
DefaultDependencies=no
[Service]
Type=exec
ExecStart=/usr/lib/tpm2-totp/show-tpm2-totp
StandardOutput=tty
[Install]
WantedBy=sysinit.target
/usr/lib/systemd/system/sysinit.target.wants/tpm2-totp.service needs to be a symlink to that unit file:
sudo ln -s ../tpm2-totp.service /usr/lib/systemd/system/sysinit.target.wants/
/etc/initcpio/install/sd-tpm2-totp:
#!/bin/bash
build() {
local mod
if [[ $TPM_MODULES ]]; then
for mod in $TPM_MODULES; do
add_module "$mod"
done
else
add_all_modules /tpm/
fi
add_systemd_unit tpm2-totp.service
add_file /usr/lib/udev/rules.d/*tpm-udev.rules
add_binary tpm2-totp
add_binary /usr/lib/libtss2-tcti-device.so.0
add_binary date
}
/etc/mkinitcpio.conf
needs to have sd-tpm2-totp
anywhere in HOOKS
:
[...]
HOOKS=(base systemd [...] sd-tpm2-totp [...])
[...]
Now regenerate the initramfs and reboot:
sudo mkinitcpio -P
I'll add some more explanation as a separate comment.
The unit always gets started way too late in the boot process, long after
systemd-ask-password-console.service
.
Your unit file generally looks fine, but seems to lack a target specification when it should be executed, which might explain why it is executed too late: the service needs to be started as part of sysinit.target
, which the commented out WantedBy=sysinit.target
is supposed to achieve.
However, mkinitcpio doesn't create the necessary symlink to actually enable it automatically, so you have to create it yourself, see the ln -s
command from my first comment. This is also what we do in tpm2-totp for the plymouth service during installation.
Also,
tpm2-totp
seemed to fail on first invocation during initramfs stage with:tpm2-totp[…]: failed to allocate dbus proxy object: Could not connect: No such file or directory
Could this be a side effect of havingtpm2-abrmd
installed? I saw that it uses dbus andusr/lib/libtss2-tcti-tabrmd.so
got included in the initramfs.
libtss2-tcti-tabrmd.so
gets pulled in by the sd-encrypt
hook. This is not really useful since I don't think D-Bus is already up at that point, so tpm2-abrmd wouldn't work anyway. On the other hand, it should only generate an annoying, but harmless error message, then continue to try using libtss2-tcti-device.so.0
instead, which should hopefully succeed. I'll look into getting the sd-encrypt
hook fixed; as a workaround, it would be possible to set the environment variable TPM2TOTP_TCTI=device
(e.g. by using Environment="TPM2TOTP_TCTI=device"
in the unit file) to suppress the error message.
On a side note - I haven't researched how to stop the service after the
initrd.target
. Right now it keeps lingering in the booted system until stopped manually.
This should be handled by the Conflicts=multi-user.target
directive in the unit file above: once user space is reached and this target is active, tpm2-totp.service
should get stopped in turn.
Thanks alot, that fixed it :)
The critical missing thing was actually the manual symlink in /usr/lib/systemd/system/sysinit.target.wants/
.
I had enabled the unit using systemctl enable tpm2-totp.service
, but that - of course - only created a symlink in /etc/systemd/system/sysinit.target.wants
, which is not picked up by the systemd
hook (not sure if this behavior is sensible, as well as ignoring units in /etc/systemd/system
- It kinda creates two disjunct modes of managing the system with systemd :/)
The first TOTP gets displayed 1-2 seconds after the LUKS password prompt, so still suboptimal, but at least it's there at all.
systemd-analyze plot
actually shows that the unit get started correctly before systemd-ask-password-console.service
, so that seems to be due to the latency of interacting with the tpm.
On a related note, I'm not entirely sure if StandardOutput=tty
is the most general option, as I'm not sure if it also displays correctly when booting over e.g. serial. If someone knows of a more canonical way of displaying output during boot, please let me know.
Oh, and just to clarify: my sd-tpm2-totp
install hook was used in addition to the original tpm2-totp
hook for testing, so the rest of the original initramfs generation logic was still in place.
BTW, you use the $TPM_MODULES
variable - so should the tpm_tis
module be added to MODULES=(…)
or to this separate variable?
I can try preparing a pull requests in the coming days if you so desire.
Thanks alot, that fixed it :)
Great to hear :)
The critical missing thing was actually the manual symlink in
/usr/lib/systemd/system/sysinit.target.wants/
. I had enabled the unit usingsystemctl enable tpm2-totp.service
, but that - of course - only created a symlink in/etc/systemd/system/sysinit.target.wants
, which is not picked up by thesystemd
hook (not sure if this behavior is sensible, as well as ignoring units in/etc/systemd/system
- It kinda creates two disjunct modes of managing the system with systemd :/)
Yeah, that's very confusing indeed - I guess this should be fixed in mkinitcpio as well so that units under the /etc
hierarchy are recognised as well.
The first TOTP gets displayed 1-2 seconds after the LUKS password prompt, so still suboptimal, but at least it's there at all.
systemd-analyze plot
actually shows that the unit get started correctly beforesystemd-ask-password-console.service
, so that seems to be due to the latency of interacting with the tpm.
Same here, I think it's just the kernel module taking some time to load (which might have a somewhat low priority during boot).
On a related note, I'm not entirely sure if
StandardOutput=tty
is the most general option, as I'm not sure if it also displays correctly when booting over e.g. serial. If someone knows of a more canonical way of displaying output during boot, please let me know.
I think it should be fine, according to the systemd.exec documentation the standard TTY is /dev/console
, so it should also work over serial (but I am by no means an expert).
BTW, you use the
$TPM_MODULES
variable - so should thetpm_tis
module be added toMODULES=(…)
or to this separate variable?
The $TPM_MODULES
variable controls which kernel modules get included into the initramfs, so you could make the file a little bit smaller by specifying only the modules you need and omit the rest.
In contrast, the mkinitcpio MODULES
array controls which kernel modules actually get loaded during boot: this is done by systemd-modules-load.service
(which must therefore be started before tpm2-totp.service
). It reads configuration files from /etc/modules-load.d/*.conf
containing one module name per line and loads them. mkinitcpio automatically creates such a configuration file from the contents of the MODULES
array and writes it to /etc/modules-load.d/MODULES.conf
.
I am not sure whether there is a better way than specifying the required kernel module statically: usually it is better to just include the necessary modules and let udev to do its job to load them on demand. That's what we do for plymouth-tpm2-totp.service
as well (the dev-tpm0.device
is automagically generated by systemd once /dev/tpm0
appears), but I haven't been able to get that to work here yet.
I can try preparing a pull requests in the coming days if you so desire.
Sure, that would be great :tada:
I am not sure whether there is a better way than specifying the required kernel module statically: usually it is better to just include the necessary modules and let udev to do its job to load them on demand. That's what we do for
plymouth-tpm2-totp.service
as well (thedev-tpm0.device
is automagically generated by systemd once/dev/tpm0
appears), but I haven't been able to get that to work here yet.
Never mind, I just forgot to include the udev rules file in the sd-tpm2-totp
hook, which is needed to create the dev-tpm0.device
device unit. I have updated my first comment, further testing would be much appreciated if you have the time :)
This way, the unit file and install hook look pretty similar to the existing plymouth-tpm2-totp.service.in
and sd-plymouth-tpm2-totp.in
for plymouth.
Thanks for the quick replies :)
Never mind, I just forgot to include the udev rules file in the
sd-tpm2-totp
hook, which is needed to create thedev-tpm0.device
device unit. I have updated my first comment, further testing would be much appreciated if you have the time :)This way, the unit file and install hook look pretty similar to the existing
plymouth-tpm2-totp.service.in
andsd-plymouth-tpm2-totp.in
for plymouth.
Yeah, I realized and implemented that in the meantime as well - taking the plymouth fix from #74 serves as a pretty good skeleton.
Preliminary local PKGBUILD based on tpm2-totp-git
from AUR works fine. I'll polish up my code and try to push later today.
Anything special to consider before making a pull request?
Preliminary local PKGBUILD based on
tpm2-totp-git
from AUR works fine. I'll polish up my code and try to push later today.
Awesome :) I'll start a new release cycle once this has been merged as well.
Anything special to consider before making a pull request?
Keeping the structure similar to #75 seems like a good idea, otherwise nothing special as far as I can think of - we use the Developers Certificate of Origin, so remember to signoff your commits (git commit -s
).
Is the D-Bus/tpm2-abrmd error message still present in your local testing? In that case, I'd include the Environment="TPM2TOTP_TCTI=device:/dev/tpm0"
in the unit file as suggested above as a workaround to silence the error until the sd-encrypt
hook is fixed. (The unit file already depends on dev-tpm0.device
anyway, so the explicit specification of the TPM device is fine.)
Similar to #74, TOTP is not displayed when using systemd initramfs, i.e. following
mkinitcpio.conf
hooks on Arch:HOOKS=(… systemd tpm2-totp …)
I tried writing a small systemd unit file and accompanying installation hook, but no luck. I checked that all the files are present in the initramfs with
lsinitcpio
and tried to trace unit execution withsystemd-analyze plot
. The unit always gets started way too late in the boot process, long aftersystemd-ask-password-console.service
.Also,
tpm2-totp
seemed to fail on first invocation during initramfs stage with:tpm2-totp[…]: failed to allocate dbus proxy object: Could not connect: No such file or directory
Could this be a side effect of havingtpm2-abrmd
installed? I saw that it uses dbus andusr/lib/libtss2-tcti-tabrmd.so
got included in the initramfs.On a side note - I haven't researched how to stop the service after the
initrd.target
. Right now it keeps lingering in the booted system until stopped manually.Thanks for writing awesome tpm2 tools ;)
For reference, the systemd unit (commented out parameters are from exploring possible permutations):
tpm2-totp.service
… and a small install hook:
sd-tpm2-totp
NOTE: The unit has to be installed in
/usr/lib/systemd/system
, not/etc/systemd/system
, otherwise theadd_systemd_unit
function fails silently duringmkinitcpio
and the unit doesn't get included in the initramfs.