Re: [systemd-devel] Issues supporting systems with and without TPM and firmware TPM (was Re: Handle device node timeout?)

2024-02-19 Thread Andrei Borzenkov
On Mon, Feb 19, 2024 at 11:37 AM Mikko Rapeli  wrote:
>
> Hi,
>
> On Fri, Feb 16, 2024 at 11:28:31AM +0200, Mikko Rapeli wrote:
> > Hi,
> >
> > Following up to my previous question which worked around with
> > Wants: and After: to dev-tpmrm0.device and tee-supplicant@teepriv0.service,
> > which don't seem to work fully.
> >
> > In short, I want to support devices with and without TPM. The TPM device
> > can also be a firmware fTPM device which depends on tee-supplicant in 
> > userspace
> > for RPMB storage.
> >
> > If TPM device is found, systemd repart in initramfs will create an 
> > encrypted rootfs
> > and if not a plaintext ext4 partition.
> >
> > Support for TPM devices is ok and drivers are built into kernel. systemd 
> > repart config
> > for rootfs is:
> >
> > [Partition]
> > Type=root
> > Weight=100
> > Format=ext4
> > Encrypt=tpm2
> > FactoryReset=yes
> > MakeDirectories=/boot /usr /home /home/root
> > # copying etc from build time /usr image
> > CopyFiles=/usr/etc:/etc
> >
> > /usr partition generated at build time is dm-verity protected and contains
> > /etc which is copied over to newly created rootfs.
> >
> > Support for fTPM devices is problematic. First, the kernel support must be 
> > modules
> > but loading needs to be specially handled after starting tee-supplicant. 
> > For normal
> > boot udev handles optee detection and triggers 
> > tee-supplicant@teepriv0.service
> > startup which unloads tpm_ftpm_tee kernel module, starts tee-supplicant and 
> > then
> > loads the kernel module again. After this RPMB works. To do the same in 
> > initramfs, I added
> > Wants: and After: dependencies from systemd-repart.service, 
> > systemd-cryptsetup@.service,
> > systemd-pcrmachine.service and systemd-pcrphase-initrd.service:
> >
> > After=dev-tpmrm0.device tee-supplicant@teepriv0.service
> > Wants=dev-tpmrm0.device tee-supplicant@teepriv0.service
>
> I think my problems come from:
>
> After=tee-supplicant@teepriv0.service
> Wants=tee-supplicant@teepriv0.service
>
> Basically tee-supplicant should only be started if /dev/teepriv* device node
> is available. Then in my case with fTPM devices, all TPM using and encrypted
> rootfs creating services need to depend on the service which starts 
> tee-supplicant
> but only if /dev/teepriv0 exists. If teepriv0 doesn't exist, then 
> tee-supplicant
> should not be started and the dependencies to it should not exist either.
>

The standard way to start a unit when a device becomes available is to
set SYSTEMD_WANTS udev property for this device.

> How should this dependency be expressed in systemd services?
>
> Can tee-supplicant@.service include:
>
> Before=systemd-pcrphase-initrd.service systemd-pcrphase.service 
> systemd-pcrmachine.service
> WantedBy=systemd-pcrphase-initrd.service systemd-pcrphase.service 
> systemd-pcrmachine.service
>

If those service has to be started only if tee-supplicant is also
started, this is backward. tee-supplicant@ needs to pull in these
services, not another way round.

> In my testing this does not seem to work inside initramfs.
>
> If systemd-pcrphase-initrd.service systemd-pcrphase.service and 
> systemd-pcrmachine.service
> service have After= and Wants= to tee-supplicant@teepriv0.service then things 
> work,
> except on boards which have no optee and no /dev/teepriv0 where 
> tee-supplicant seems
> be started and fails due to missing optee which breaks the initramfs boot.
>
> Cheers,
>
> -Mikko
>
> > The base tee-supplicant@.service is:
> >
> > [Unit]
> > Description=TEE Supplicant on %i
> > # Needs to be started earlier
> > DefaultDependencies=no
> > Conflicts=shutdown.target initrd-switch-root.target
> > Before=local-fs-pre.target cryptsetup-pre.target cryptsetup.target 
> > shutdown.target initrd-switch-root.target systemd-sysext.service
> > Before=systemd-pcrphase-initrd.service systemd-pcrphase.service 
> > systemd-pcrmachine.service
> >
> > [Service]
> > User=root
> > EnvironmentFile=-@sysconfdir@/default/tee-supplicant
> > ExecStartPre=-@sbindir@/modprobe -r tpm_ftpm_tee
> > ExecStartPre=@sbindir@/create-tee-supplicant-env 
> > @localstatedir@/run/tee-supplicant.env
> > ExecStart=/bin/sh -c "if [ -c /dev/teepriv0 ]; then 
> > @sbindir@/tee-supplicant $RPMB_CID $OPTARGS; fi"
> > ExecStartPost=-/bin/sh -c "while [ ! $(pgrep tee-supplicant) ]; do sleep 
> > 0.1; done; /sbin/modprobe tpm_ftpm_tee"
> > ExecStop=-/sbin/modprobe -r tpm_ftpm_tee
> >
> > [Install]
> > # fTPM encrypted filesystems, needs to start in initrd stage
> > WantedBy=local-fs-pre.target
> >
> > These seem to work for devices with and without TPM, but on devices with 
> > missing optee
> > and /dev/teepriv0 not. The missing TPM device is detected after timeout, 
> > which is ok,
> > and the fallback to unencrypted ext4 happens since systemd-repart.service 
> > has:
> >
> > ExecStart=/bin/sh -c "/usr/bin/test -c /dev/tpmrm0 && 
> > /usr/bin/systemd-repart --dry-run=no 
> > --definitions=${nonarch_libdir}/repart.d/ || /usr/bin/systemd-repart 
> 

Re: [systemd-devel] Issues supporting systems with and without TPM and firmware TPM (was Re: Handle device node timeout?)

2024-02-19 Thread Lennart Poettering
On Mo, 19.02.24 10:36, Mikko Rapeli (mikko.rap...@linaro.org) wrote:

> > After=dev-tpmrm0.device tee-supplicant@teepriv0.service
> > Wants=dev-tpmrm0.device tee-supplicant@teepriv0.service
>
> I think my problems come from:
>
> After=tee-supplicant@teepriv0.service
> Wants=tee-supplicant@teepriv0.service
>
> Basically tee-supplicant should only be started if /dev/teepriv* device node
> is available. Then in my case with fTPM devices, all TPM using and encrypted
> rootfs creating services need to depend on the service which starts 
> tee-supplicant
> but only if /dev/teepriv0 exists. If teepriv0 doesn't exist, then 
> tee-supplicant
> should not be started and the dependencies to it should not exist
> either.

Is /dev/teepriv* guaranteed to be available when userspace is invoked?
or is it something that itself requires some kmod loading to show up,
i.e. that "udevadm trigger" causes to load?

> How should this dependency be expressed in systemd services?
>
> Can tee-supplicant@.service include:
>
> Before=systemd-pcrphase-initrd.service systemd-pcrphase.service 
> systemd-pcrmachine.service
> WantedBy=systemd-pcrphase-initrd.service systemd-pcrphase.service 
> systemd-pcrmachine.service
>
> In my testing this does not seem to work inside initramfs.
>
> If systemd-pcrphase-initrd.service systemd-pcrphase.service and 
> systemd-pcrmachine.service
> service have After= and Wants= to tee-supplicant@teepriv0.service then things 
> work,
> except on boards which have no optee and no /dev/teepriv0 where 
> tee-supplicant seems
> be started and fails due to missing optee which breaks the initramfs boot.

For your usecase the new tpm2.target available in git main is what you
really should focus on: all TPM using services should order themselves
after that. All stuff needed to make a TPM device appear should be
placed before that.

The systemd-tpm2-generator that now exists in git main analyzes the
uefi/acpi firmware situation and automatically adds a dev-tpm0.device
dependency on tpm2.target if it comes to the conclusion that such a
device will show up. This generator is not going to cover your
specific case, but I think it would be a good blueprint for you:
i.e. write a generator that checks if /dev/teepriv* exists. If not,
just exit. If yes, generate the required deps to pull in
tee-supplicatnt@.service, and add the dev-tpmrm0.device dep just like
systemd-tpm2-generator does.

Lennart

--
Lennart Poettering, Berlin


Re: [systemd-devel] Issues supporting systems with and without TPM and firmware TPM (was Re: Handle device node timeout?)

2024-02-19 Thread Lennart Poettering
On Fr, 16.02.24 11:28, Mikko Rapeli (mikko.rap...@linaro.org) wrote:

> Support for fTPM devices is problematic. First, the kernel support must be 
> modules
> but loading needs to be specially handled after starting tee-supplicant. For 
> normal
> boot udev handles optee detection and triggers tee-supplicant@teepriv0.service
> startup which unloads tpm_ftpm_tee kernel module, starts tee-supplicant and 
> then
> loads the kernel module again. After this RPMB works. To do the same in 
> initramfs, I added
> Wants: and After: dependencies from systemd-repart.service, 
> systemd-cryptsetup@.service,
> systemd-pcrmachine.service and systemd-pcrphase-initrd.service:

Kernel module unloading is not supposed to happen in clean
codepaths. It's a debug/development feature, it's not safe to do as
part of regular boot.

But why do you need an unload a kernel module at all? that smells...

Lennart

--
Lennart Poettering, Berlin


Re: [systemd-devel] Handle device node timeout?

2024-02-19 Thread Lennart Poettering
On Di, 16.01.24 16:06, Mikko Rapeli (mikko.rap...@linaro.org) wrote:

> Hi,
>
> I have services which depend on a specific device node. How can I run
> some recovery actions when the default 90s timeout for finding this
> device is hit?
>
> OnFailure= doesn't work as the service is not even started.
>
> Specifically the case is about supporting TPM2 encrypted rootfs but falling
> back to plain-text rootfs generation if there is no TPM2 device. Currently
> my initramfs works with TPM2 but without it fails with:

In git main there's new infra to deal with this case:

https://github.com/systemd/systemd/pull/30194

That should hopefully solve this systematically and generically.

Lennart

--
Lennart Poettering, Berlin


Re: [systemd-devel] Issues supporting systems with and without TPM and firmware TPM (was Re: Handle device node timeout?)

2024-02-19 Thread Mikko Rapeli
Hi,

On Fri, Feb 16, 2024 at 11:28:31AM +0200, Mikko Rapeli wrote:
> Hi,
> 
> Following up to my previous question which worked around with
> Wants: and After: to dev-tpmrm0.device and tee-supplicant@teepriv0.service,
> which don't seem to work fully.
> 
> In short, I want to support devices with and without TPM. The TPM device
> can also be a firmware fTPM device which depends on tee-supplicant in 
> userspace
> for RPMB storage.
> 
> If TPM device is found, systemd repart in initramfs will create an encrypted 
> rootfs
> and if not a plaintext ext4 partition.
> 
> Support for TPM devices is ok and drivers are built into kernel. systemd 
> repart config
> for rootfs is:
> 
> [Partition]
> Type=root
> Weight=100
> Format=ext4
> Encrypt=tpm2
> FactoryReset=yes
> MakeDirectories=/boot /usr /home /home/root
> # copying etc from build time /usr image
> CopyFiles=/usr/etc:/etc
> 
> /usr partition generated at build time is dm-verity protected and contains
> /etc which is copied over to newly created rootfs.
> 
> Support for fTPM devices is problematic. First, the kernel support must be 
> modules
> but loading needs to be specially handled after starting tee-supplicant. For 
> normal
> boot udev handles optee detection and triggers tee-supplicant@teepriv0.service
> startup which unloads tpm_ftpm_tee kernel module, starts tee-supplicant and 
> then
> loads the kernel module again. After this RPMB works. To do the same in 
> initramfs, I added
> Wants: and After: dependencies from systemd-repart.service, 
> systemd-cryptsetup@.service,
> systemd-pcrmachine.service and systemd-pcrphase-initrd.service:
> 
> After=dev-tpmrm0.device tee-supplicant@teepriv0.service
> Wants=dev-tpmrm0.device tee-supplicant@teepriv0.service

I think my problems come from:

After=tee-supplicant@teepriv0.service
Wants=tee-supplicant@teepriv0.service

Basically tee-supplicant should only be started if /dev/teepriv* device node
is available. Then in my case with fTPM devices, all TPM using and encrypted
rootfs creating services need to depend on the service which starts 
tee-supplicant
but only if /dev/teepriv0 exists. If teepriv0 doesn't exist, then tee-supplicant
should not be started and the dependencies to it should not exist either.

How should this dependency be expressed in systemd services?

Can tee-supplicant@.service include:

Before=systemd-pcrphase-initrd.service systemd-pcrphase.service 
systemd-pcrmachine.service
WantedBy=systemd-pcrphase-initrd.service systemd-pcrphase.service 
systemd-pcrmachine.service

In my testing this does not seem to work inside initramfs.

If systemd-pcrphase-initrd.service systemd-pcrphase.service and 
systemd-pcrmachine.service
service have After= and Wants= to tee-supplicant@teepriv0.service then things 
work,
except on boards which have no optee and no /dev/teepriv0 where tee-supplicant 
seems
be started and fails due to missing optee which breaks the initramfs boot.

Cheers,

-Mikko

> The base tee-supplicant@.service is:
> 
> [Unit]
> Description=TEE Supplicant on %i
> # Needs to be started earlier
> DefaultDependencies=no
> Conflicts=shutdown.target initrd-switch-root.target
> Before=local-fs-pre.target cryptsetup-pre.target cryptsetup.target 
> shutdown.target initrd-switch-root.target systemd-sysext.service
> Before=systemd-pcrphase-initrd.service systemd-pcrphase.service 
> systemd-pcrmachine.service
> 
> [Service]
> User=root
> EnvironmentFile=-@sysconfdir@/default/tee-supplicant
> ExecStartPre=-@sbindir@/modprobe -r tpm_ftpm_tee
> ExecStartPre=@sbindir@/create-tee-supplicant-env 
> @localstatedir@/run/tee-supplicant.env
> ExecStart=/bin/sh -c "if [ -c /dev/teepriv0 ]; then @sbindir@/tee-supplicant 
> $RPMB_CID $OPTARGS; fi"
> ExecStartPost=-/bin/sh -c "while [ ! $(pgrep tee-supplicant) ]; do sleep 0.1; 
> done; /sbin/modprobe tpm_ftpm_tee"
> ExecStop=-/sbin/modprobe -r tpm_ftpm_tee
> 
> [Install]
> # fTPM encrypted filesystems, needs to start in initrd stage
> WantedBy=local-fs-pre.target
> 
> These seem to work for devices with and without TPM, but on devices with 
> missing optee
> and /dev/teepriv0 not. The missing TPM device is detected after timeout, 
> which is ok,
> and the fallback to unencrypted ext4 happens since systemd-repart.service has:
> 
> ExecStart=/bin/sh -c "/usr/bin/test -c /dev/tpmrm0 && /usr/bin/systemd-repart 
> --dry-run=no --definitions=${nonarch_libdir}/repart.d/ || 
> /usr/bin/systemd-repart --dry-run=no 
> --definitions=${nonarch_libdir}/repart.d_notpm/"
> 
> But the missing optee and /dev/teepriv0 causes issues where 
> tee-supplicant@teepriv0.service gets
> started in initramfs stage but since optee is not found from firmware 
> tee-supplicant exits with error.
> 
> So what could be done better or correctly?
> 
> The problematic part is to run these tee-supplicant and tpm_ftpm_tee loading 
> steps
> only when /dev/teepriv0 is available and early enough for TPM2 dependencies 
> to work
> for systemd.
> 
> Should I rather setup a dedicated service for initramfs