Skip to content

Enable full static linking of libtss2 when using "bundled" feature - #686

Merged
ionut-arm merged 4 commits into
parallaxsecond:mainfrom
ThatGeoGuy:main
Oct 1, 2026
Merged

ionut-arm merged 4 commits into
parallaxsecond:mainfrom
ThatGeoGuy:main

Conversation

@ThatGeoGuy

Copy link
Copy Markdown
Contributor

On the Slack I had made the assumption that the "bundled" feature implied that the sys library was statically linked; I was corrected (by @ionut-arm) that this was not in fact true:

image

But of course, my confusion arose from the fact that when I did build/link with bundled, I saw the following in my target/ directory:

$ ls -Tahl target/release-with-debug/build/tss-esapi-sys-9d14cbaeeb93a50d/out/lib
Permissions Size User   Date Modified Name
drwxrwxr-x     - jeremy 24 Aug 14:26  target/release-with-debug/build/tss-esapi-sys-9d14cbaeeb93a50d/out/lib
.rw-r--r--  8.6M jeremy 24 Aug 14:26  ├── libtss2-esys.a
.rwxr-xr-x  1.2k jeremy 24 Aug 14:26  ├── libtss2-esys.la
.rw-r--r--  2.4M jeremy 24 Aug 14:26  ├── libtss2-mu.a
.rwxr-xr-x   988 jeremy 24 Aug 14:26  ├── libtss2-mu.la
.rw-r--r--  5.2M jeremy 24 Aug 14:26  ├── libtss2-policy.a
.rwxr-xr-x  1.4k jeremy 24 Aug 14:26  ├── libtss2-policy.la
.rw-r--r--   74k jeremy 24 Aug 14:26  ├── libtss2-rc.a
.rwxr-xr-x   988 jeremy 24 Aug 14:26  ├── libtss2-rc.la
.rw-r--r--  3.3M jeremy 24 Aug 14:26  ├── libtss2-sys.a
.rwxr-xr-x  1.1k jeremy 24 Aug 14:26  ├── libtss2-sys.la
.rw-r--r--  198k jeremy 24 Aug 14:26  ├── libtss2-tcti-cmd.a
.rwxr-xr-x  1.1k jeremy 24 Aug 14:26  ├── libtss2-tcti-cmd.la
.rw-r--r--  241k jeremy 24 Aug 14:26  ├── libtss2-tcti-device.a
.rwxr-xr-x  1.1k jeremy 24 Aug 14:26  ├── libtss2-tcti-device.la
.rw-r--r--  245k jeremy 24 Aug 14:26  ├── libtss2-tcti-i2c-helper.a
.rwxr-xr-x  1.1k jeremy 24 Aug 14:26  ├── libtss2-tcti-i2c-helper.la
.rw-r--r--  237k jeremy 24 Aug 14:26  ├── libtss2-tcti-mssim.a
.rwxr-xr-x  1.1k jeremy 24 Aug 14:26  ├── libtss2-tcti-mssim.la
.rw-r--r--  273k jeremy 24 Aug 14:26  ├── libtss2-tcti-pcap.a
.rwxr-xr-x  1.3k jeremy 24 Aug 14:26  ├── libtss2-tcti-pcap.la
.rw-r--r--  336k jeremy 24 Aug 14:26  ├── libtss2-tcti-spi-helper.a
.rwxr-xr-x  1.1k jeremy 24 Aug 14:26  ├── libtss2-tcti-spi-helper.la
.rw-r--r--  144k jeremy 24 Aug 14:26  ├── libtss2-tcti-spidev.a
.rwxr-xr-x  1.3k jeremy 24 Aug 14:26  ├── libtss2-tcti-spidev.la
.rw-r--r--  237k jeremy 24 Aug 14:26  ├── libtss2-tcti-swtpm.a
.rwxr-xr-x  1.1k jeremy 24 Aug 14:26  ├── libtss2-tcti-swtpm.la
.rw-r--r--  212k jeremy 24 Aug 14:26  ├── libtss2-tctildr.a
.rwxr-xr-x  1.0k jeremy 24 Aug 14:26  ├── libtss2-tctildr.la
drwxrwxr-x     - jeremy 24 Aug 14:26  ├── pkgconfig
.rw-r--r--   452 jeremy 24 Aug 14:26  │   ├── tss2-esys.pc
.rw-r--r--   399 jeremy 24 Aug 14:26  │   ├── tss2-mu.pc
.rw-r--r--   381 jeremy 24 Aug 14:26  │   ├── tss2-policy.pc
.rw-r--r--   381 jeremy 24 Aug 14:26  │   ├── tss2-rc.pc
.rw-r--r--   420 jeremy 24 Aug 14:26  │   ├── tss2-sys.pc
.rw-r--r--   449 jeremy 24 Aug 14:26  │   ├── tss2-tcti-cmd.pc
.rw-r--r--   451 jeremy 24 Aug 14:26  │   ├── tss2-tcti-device.pc
.rw-r--r--   431 jeremy 24 Aug 14:26  │   ├── tss2-tcti-i2c-helper.pc
.rw-r--r--   460 jeremy 24 Aug 14:26  │   ├── tss2-tcti-mssim.pc
.rw-r--r--   426 jeremy 24 Aug 14:26  │   ├── tss2-tcti-pcap.pc
.rw-r--r--   431 jeremy 24 Aug 14:26  │   ├── tss2-tcti-spi-helper.pc
.rw-r--r--   453 jeremy 24 Aug 14:26  │   ├── tss2-tcti-spidev.pc
.rw-r--r--   437 jeremy 24 Aug 14:26  │   ├── tss2-tcti-swtpm.pc
.rw-r--r--   416 jeremy 24 Aug 14:26  │   └── tss2-tctildr.pc
drwxrwxr-x     - jeremy 24 Aug 14:26  └── udev
drwxrwxr-x     - jeremy 24 Aug 14:26      └── rules.d
.rw-r--r--   230 jeremy 24 Aug 14:26          └── tpm-udev.rules

So obviously it's building the library statically, and I didn't do anything with pkg-config to ask it to, but this still requires the dynamic library at runtime. This implied a runtime library, but in terms of running ldd <program> on my software, I could only see that it was statically linked.

My coworker pointed me to the libtss2 repo, and specifically this line. Turns out you have to set --enable-nodl with autoconf to get "full static linking." This also means you have to explicitly link libtss2-tcti-device, libtss2-tcti-mssim, and libtss2-tcti-swtpm, since the library won't dlopen those itself anymore (and cargo will complain about missing symbols).

Anyways, lesson learned, the "bundled" feature does provide static linking today. It just wasn't 100% static. I am providing a patch to do full static linking via the bundled feature, with the assumption that if you're bundling the library, you want it to be 100% static. I did not split this into "bundled" and "bundled-100%-static-I-swear," which could be done, but seemed odd to me. I will admit I don't know the full scope of use-cases or users of the library though, so maybe that should be how this was implemented.

On LLMs / Copyright

I got the impression by the Developer Certificate of Origin (and the fact there are no LLM commits in the main branch from what I can see) that LLM contributions are not welcome. Consequently, I wrote all the commits myself. There's not really much there, and I only really worked on the autotools version of things. I'm sure if you wanted you could burn a (quite large) sum of tokens to verify this further.

Which leads me to another point...

Testing / Windows / etc support

I created a small example program where I could enable and disable the "bundled" feature. I then used ldd, readelf -d, and strings to check that the expected symbols were compiled statically into the program. I don't have a good way to automate this, and I'm not sure how you would want to test this in your CI configuration. I read the testing section in the contributing guide, and I don't know the degree to which statically linking the way I'm doing here with autotools could or would cause security problems/changed expectations downstream of the project.

I did not test Windows whatsoever. While I found the --enable-nodl option for autotools thanks to my coworker, I have no knowledge of msbuild or how to finagle that to do something similar. I think it would probably be helpful if someone who can test on Windows could advise if it's necessary or not, or if static linking is even feasible there. Regrettably, I am not working on Windows at all and have no plans to purchase a Windows machine to test static linking, but if there's an easy way to enable it I'm more than happy to push on top of this branch.

Lastly: as I mentioned above there's no automated testing for this. I will further admit I don't know how GitHub Actions works, or if there's a way that you want this to be tested in practice. We use GitLab at work and I don't want to inject something that would annoy day-to-day development. ¯_(ツ)_/¯

Comment thread tss-esapi-sys/build.rs
@ThatGeoGuy

Copy link
Copy Markdown
Contributor Author

One additional comment: something that confused me initially as well was that you could use the "bundled" feature to get around the minimum version restriction (v4.1.3), but then when calling dlopen the library would grab whatever was on your system. Locally, I'm on Ubuntu 24.04, so this was v4.0.1, and it "just worked" because the symbol versions were the same, even if the library version was different.

But this isn't what you expect if you bundle 4.1.3, you expect to be using the tcti libraries from 4.1.3. I think it's something of a risk to accidentally get "downgraded" even if (at least, for what I was using it for) it just worked™. But this is sort of theoretical, and sort of just because I don't have a clean setup locally.

So there may be something to think about there. As I'm not intimately familiar with every part of libtss2, I can't lay claim to anything with regards to security or how one should assess those facts.

@ThatGeoGuy

Copy link
Copy Markdown
Contributor Author

Also I'm not sure how related #653 is here.

It seems like it goes in a different direction, and I figured it would be better to use the official autoconf setting --enable-nodl rather than stub the loader out as was done there. Maybe @indirect can comment on whether one of these should be closed/extended in favour of the other?

Signed-off-by: Jeremy Steward <jeremy.steward@tangramvision.com>
Signed-off-by: Jeremy Steward <jeremy.steward@tangramvision.com>
The TCTI libraries have a runtime library, which can be disabled in
autoconf with `--enable-nodl`. This is why when you "bundle" the
statically linked build of libtss2, you still need to provide the
dynamic libraries at runtime. Specifically, the "bundled" TCTI libraries
will `dlopen` the swtpm, device, and mssim libraries at runtime,
despite any binary actually appearing statically linked to libtss2.

Signed-off-by: Jeremy Steward <jeremy.steward@tangramvision.com>
@indirect

Copy link
Copy Markdown

This sounds like it could replace #653, as long as this build stops trying to call dlopen. Works for me. 👍🏻

@Superhepper

Copy link
Copy Markdown
Collaborator

One additional comment: something that confused me initially as well was that you could use the "bundled" feature to get around the minimum version restriction (v4.1.3), but then when calling dlopen the library would grab whatever was on your system. Locally, I'm on Ubuntu 24.04, so this was v4.0.1, and it "just worked" because the symbol versions were the same, even if the library version was different.

But this isn't what you expect if you bundle 4.1.3, you expect to be using the tcti libraries from 4.1.3. I think it's something of a risk to accidentally get "downgraded" even if (at least, for what I was using it for) it just worked™. But this is sort of theoretical, and sort of just because I don't have a clean setup locally.

I am not sure how @uglyoldbob was imagine it to work when he created the initial PR but the way I imagined it to work was that it would only provide everything necessary for building and what you use when you are actually running it will depend on you and what you chose to use.
Now it is quite possible that messed things up when trying to fix some problems and that half of it actually got statically linked while TCTIs was still dynamically linked so that would go against how I imagined it to work.
So it is nice that you fixed it made it all statically linked.

So there may be something to think about there. As I'm not intimately familiar with every part of libtss2, I can't lay claim to anything with regards to security or how one should assess those facts.

@ThatGeoGuy

Copy link
Copy Markdown
Contributor Author

but the way I imagined it to work was that it would only provide everything necessary for building and what you use when you are actually running it will depend on you and what you chose to use.

@Superhepper I believe you're right that the intent is that you would actually use the same version that you bundled in practice, and I imagine that's probably the correct posture to take, since if you accidentally used e.g. a 3.x version of the library while bundling 4.1.3 you'd be in for a bad time.

Still though, that requires some care to make sure that you ship with the same version that you bundle for, and that you don't configure something incorrectly (e.g. have an additional, separate version in /usr/local that gets used unexpectedly). My hope with this is that by using the bundled version without dlopen you're avoiding this set of hassles entirely :)

@Superhepper

Copy link
Copy Markdown
Collaborator

Support for windows is experimental (at best) so I would not worry to much about it.

Superhepper
Superhepper previously approved these changes Sep 26, 2026
@Superhepper

Copy link
Copy Markdown
Collaborator

Testing that static linking works would probably require moving the test binary somewhere else entirely and then make sure there is nothing in the PATH and then try to run the tests.

@ionut-arm ionut-arm left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for putting in the effort and for the thorough write-up! My only request is for some docs.

Comment thread tss-esapi-sys/build.rs
@ThatGeoGuy

Copy link
Copy Markdown
Contributor Author

Addressed the doc comments in a6d9226. Happy to add more if you think there's some other piece of documentation you want me to write.

@ThatGeoGuy

Copy link
Copy Markdown
Contributor Author

@ionut-arm @Superhepper I'd like to bump this one more time: are there any more docs you'd like me to write, any tests to add?

If not I'm happy to squash my fixup and move forward.

@Superhepper

Copy link
Copy Markdown
Collaborator

Testing the static linking is something that can be done in separate commit. I imagine one would have to build the test binary and move it to like a temp folder and then run it. Or run some commands and inspect the test binary.

So no I cannot really think of anything.

@ThatGeoGuy

Copy link
Copy Markdown
Contributor Author

Testing the static linking is something that can be done in separate commit. I imagine one would have to build the test binary and move it to like a temp folder and then run it. Or run some commands and inspect the test binary.

So no I cannot really think of anything.

Great! Let me squash what I have then, so you don't have a fixup! in the history.

The actual "bundled" feature does statically link all the libraries now,
so you don't need to have TCTI libraries present at runtime.

Signed-off-by: Jeremy Steward <jeremy.steward@tangramvision.com>
@ionut-arm
ionut-arm merged commit acf3e02 into parallaxsecond:main Oct 1, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants