[systemd-devel] tee-supplicant initrd startup before tpm2.target and dev-tpmrm0.device

Mikko Rapeli mikko.rapeli at linaro.org
Fri May 24 08:43:34 UTC 2024


Hi,

On Fri, May 24, 2024 at 10:12:52AM +0200, Lennart Poettering wrote:
> On Fr, 24.05.24 10:10, Mikko Rapeli (mikko.rapeli at linaro.org) wrote:
> 
> > > > EnvironmentFile=- at sysconfdir@/default/tee-supplicant
> > > > ExecStart=@sbindir@/tee-supplicant $OPTARGS
> > > >
> > > > [Install]
> > > > WantedBy=basic.target
> > >
> > > Usually you'd hook services into "sysinit.target" not
> > > "basic.target". The job of "basic.target" is really do combine
> > > sysinit.target (i.e. early-boot services), local-fs.target
> > > (i.e. local mounts), swaps.target (swaps), sockets.target (well, you
> > > guess it), and so on.
> > >
> > > Hence, if you plug in services, use sysinit.target.
> >
> > tee-supplicant at .service needs to run early, before rootfs decryption in case of fTPM.
> > Would "WantedBy=sysinit.target" and "Before: tpm2.target" be correct
> > then?
> 
> Well, you want to run it during early boot, hence you should add
> DefaultDependencies=no and that should really suffice, given you
> actually start the thing via an udev rule.
>
> >
> > > > udev rule is:
> > > >
> > > > KERNEL=="tee[0-9]*", MODE="0660", OWNER="root", GROUP="teeclnt", TAG+="systemd"
> > > >
> > > > # If a /dev/teepriv[0-9]* device is detected, start an instance of
> > > > # tee-supplicant.service with the device name as parameter
> > > > KERNEL=="teepriv[0-9]*", MODE="0660", OWNER="root", GROUP="teeclnt", \
> > > >     TAG+="systemd", ENV{SYSTEMD_WANTS}+="tee-supplicant@%k.service"
> > > >
> > > > So basically dev-tpmrm0.device depends on tee-supplicant at teepriv0.service started
> > > > on dev-teepriv0.device by udev. How to express this dependency?
> > >
> > > I am not sure I grok this dependency chain?
> > >
> > > What do you mean by ordering the service against dev-tpmrm0.device?
> > > why would you order this? I mean, when
> > > tee-supplicant at teepriv0.service is invoked it will do its thing and
> > > synthesize a /dev/tpmrm0, right?
> >
> > Firmware has optee and an fTPM trusted app. In kernel we have the fTPM driver
> > but all of these depend also on the userspace tee-supplicant to handle optee IPC setup
> > and possibly RPMB emulation (in my case I have kernel patches for this, and native
> > support on the platforms). So the fTPM TA in optee only enumerates after tee-supplicant
> > has been started, and this in turn triggers fTPM kernel module
> > loading with udev.
> 
> I am not sure I can parse all that, but it seems the only deps you
> need are:
> 
> 1. pull in tee-supplicant@%k.service when the tee device shows up via
>    the udev rule
> 2. make sure tee-supplicant at .service has DefaultDependencies=no so
>    that it can be started in early boot.
> 3. Make sure that tee-supplicant at .service has After=dev-%i.device and
>    Wants=dev-%i.device – this part is kinda optional, given you pull
>    in the service by default only via that udev rule, and thus the
>    device has already shown up. Having these two deps explicitly is
>    still kinda useful though in case a user does "systemctl start
>    tee-suppliant at teepriv0.service" manually or so, since it makes sure
>    we'll wait for the backing device to show up.
> 
>
> And that's really all.

Thanks! Indeed my problems were caused by trying to do too much with tpm2.target
and such,  and missing the DefaultDependencies=no which was binding everything
to basic.target, thus delaying the startup of tee-supplicant.

> To summarize, a unit file like this:
> 
>     [Unit]
>     Description=TEE Supplicant on %i
>     Documentation=man:tee-supplicant(8)
>     DefaultDependencies=no
>     After=dev-%i.device
>     Wants=dev-%i.device
>     Conflicts=shutdown.target
>     Before=sysinit.target shutdown.target
> 
>     [Service]
>     ExecStart=@sbindir@/tee-supplicant -d /dev/%I
> 
> Together with a udev rule:
> 
>     KERNEL=="teepriv[0-9]*", MODE="0660", TAG+="systemd", ENV{SYSTEMD_WANTS}+="tee-supplicant@%k.service"
> 
> And that should make things work. (Well, I have no experience with any
> of this, I never touched such a platform, the above is made up without
> ever having played with this.)

Thanks. This setup sounds exactly what is needed. I'll test this out.
I tried to make too complex thing about it by mixing tpm2.target into it.
 
> If you want the ability to enable/disable the service, you could add
> an indirection via a target unit, and then add an [Install]
> section. But I am not sure that makes too much sense, given that you
> want this stuff in the initrd already?  services that can be
> enabled/disabled are usually stuff for the main system, not for the
> initrd.

I will do this since first start of tee-supplicant in initrd (or outside)
leaves the RPC buffers and kernel drivers in working state and tee-supplicant
can later be started and stopped, to for example, load trusted applications for
testing purposes.
 
> > > This shows an ordering cycle. Address that first. If you have an
> > > ordering cycle systemd will drop jobs from the initial transactions in
> > > an attempt to fix it, but it's not always clear that the one it drops
> > > it the best one to drop.
> >
> > Indeed, these ordering problems may be the root cause.
> 
> So the ordering is probably because the missing DefaultDependencies=no
> 
> > > The logs do not show that your "tee-supplicant at .service" unit gets
> > > enqueued. So are you sure your udev rule even works?
> >
> > The udev rule works. With debug logs I see:
> >
> > https://ledge.validation.linaro.org/scheduler/job/87556
> >
> > [0;38;5;245mtee-supplicant at teepriv0.service: starting held back,
> > waiting for: basic.target[0m
> 
> Yupp, that's the DefaultDependencies=no thing.
> 
> > So I think I need to disable the default dependencies with DefaultDependencies=no
> > With my limited understanding I think I would also need the tpm2.target to wait for
> > tee-supplicant startup. "WantedBy=sysinit.target tpm2.target" would do it?
> > Or alternatively in tpm2.target
> >
> > After=dev-tpmrm0.device dev-teepriv0.device
> > Wants=dev-tpmrm0.device dev-teepriv0.device
> 
> Why should tpm2.target wait for tee-supplicant startup though? it
> should be enough for the /dev/tpmrm0 device to materalize, no? And
> that hapens when tee-supplicant does its thing, hence there's no need
> to explicitly wait for that, is there?

Yes, tpm2.target should only wait for tpmrm0. I just failed to force tee-supplicant
into the mix. With DefaultDependencies=no in tee-supplicant service file
this issue should not exists. Thus systemd config would not know of the link
between optee, tee-supplicant in userspace and fTPM TA and kernel drivers. The udev
config makes sure that correct services get started and services have minimal
dependencies so that they work in initrd already.

Thanks a lot fot the clarifications and help!

Cheers,

-Mikko


More information about the systemd-devel mailing list