Here's the 15th installment of posts highlighting key new features of the upcoming v256 release of systemd.
systemd integrates with many components of the OS. Due to this it links against various external libraries. Generic distributions – which typically enable all features a package provides – usually have to deal with relatively large dependency trees in cases like this.
systemd is often used in smaller environments, i.e run in containers, or in the initrd or similar. Hence a large dependency tree is problematic.
Because of that in systemd we started to turn a large number of our dependencies from regular ones to dlopen() ones: instead of always requiring some shared library we only load it the moment we need it. This means we can gracefully degrade our feature set if certain libraries are not available.
We have been doing this since quite a while, so that in v256 22 of our dependencies have been reworked like that.
This has the benefit that on a typical system the systemd binary itself only pulls in the C library (including libm), libmount, libselinux, libaudit and libseccomp.
Net result: we have a tiny required dependency footprint, but can still provide a large feature set, if the optional deps happen to be installed.
This comes at a price though: since our library dependencies are now dlopen() based they do not show up in the ELF metadata of our binaries anymore. And package managers such as dpkg/rpm generally look at that, and automatically translate those ELF dependencies into packaging dependencies.
Hence: at first glance, this means that we regress on this front: previously automatically determined dependencies have to be encoded manually again.
With v256 we are doing something about this.
All our binaries now contain an ELF "note" describing these "weak" deps that can be processed in a similar way as regular ELF dependencies.
The format of these notes is described here:
https://github.com/systemd/systemd/blob/main/docs/ELF_DLOPEN_METADATA.md
There's now work ongoing to process this data automatically at rpm and dpkg build time, so that we get the best of both worlds: "weak" dependencies and proper metadata to declare them consistently.
For now the spec sits in systemd's repository. We intend to add it to the uapi group's repository soon though, as this really is supposed to be something not only systemd provides, but any software that is in a similar situation and uses dlopen() to gracefully import a fixed set of external libraries.
And that's all for now. Stay tuned for episode 16 soon.
(Sorry for not keeping up the pace btw, currently at a conference)
@pid_eins patches to support pretty-printing the note in readelf have been sent upstream too:
https://sourceware.org/pipermail/binutils/2024-May/134032.html
https://sourceware.org/pipermail/elfutils-devel/2024q2/007065.html
@pid_eins these are now merged in both binutils and elfutils
@pid_eins tool for Debian packages to automagically use this also available and uploaded: https://tracker.debian.org/pkg/package-notes
@bluca @pid_eins I wonder if makes sense for you: https://lore.kernel.org/linux-integrity/20240523212515.4875-1-jarkko@kernel.org/
It is somewhat practical feature: never have.private keys stored in plain text, neither in drive nor memory. TPM2 can open it but not publish it, and the public key is available for clients for encryption and verifying signatures. TPM2 decrypts and signs. So it is kind of “private halve in hardware” and “public halve in software”.
Only when the key is first created it is in plain text like:
tpm2_createprimary --hierarchy o -G rsa2048 -c owner.txt
tpm2_evictcontrol -c owner.txt 0x81000001
tpm2_getcap handles-persistent
openssl genrsa -out private.pem 2048
tpm2_import -C 0x81000001 -G rsa -i private.pem -u key.pub -r key.priv
tpm2_encodeobject -C 0x81000001 -u key.pub -r key.priv -o key.priv.pem
openssl asn1parse -inform pem -in key.priv.pem -noout -out key.priv.der
The final priv.der
can be only decrypted by the TPM when it opens it:
serial=`cat key.priv.der | keyctl padd asymmetric tpm @u`
So the point of all this is that you can use this to sign and encrypt wifi credentials (iwd), root keyrings (e.g. gnome-keyring) and sign x.509 certificates without exposing the private key once first created or acquired.
For 6.11 tpm2_key_rsa
is planned and right after that tpm2_key_ecdsa
(not sure whether in 6.11 or 6.12). Not sure if this makes sense for systemd
but I thought it might.
@pid_eins What about also moving the Credentials spec to uapi?
@pid_eins from my quick read through of the specs in the systems repo, it looks like you propose to store the section payload in json. Last time I heard about this new section idea you seemed to not want to use json so it would be possible to use simple macros to add entries to the section.
I found that to sound quite reasonable, did you change your mind about that ?
Also, how do you suggest people generate the json from their sources now ?
@zeGrandpa the c macros do generate json now, hence we get the best of both worlds: json's flexibility but still the ability to embed this data directly in c code.
@pid_eins ha yes, found them in the code, neat
@pid_eins nice, i'll consider sending a patch to add processing this to melange
@pid_eins you could have just created a dummy elf binary which is always included and links with all needed libraries.
@pid_eins Have you considered a way to require one of multiple binaries?
A common example that comes to mind is a choice of SSL libraries...
@pid_eins this sound so much like windows. Remember how attackers try to make windows load the wrong DLL to get enhanced privileges.
How do you protect against this?
@pid_eins these uncounted dependencies caused the openssh hack via liblzma.
Why do people need to link with full systemd libraries just for some communication.
Were the affected distributions wrong, and there is another way? Maybe by using sockets?
Remember: one tool to do one thing. And not one tool to do everything.