Skip to content

tpmutil: separate OpenTPM into emulation and non-emulation #364

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

leongross
Copy link

@leongross leongross commented Aug 1, 2024

To prohibit the inclusion of the "net" package, separate the build of tpmutil via build tag emu into a filesystem-based and a socket-based version.

EDIT: This PR is part of enabling tinygo support for u-root.
tinygo currently lacks sufficient linux network support, so we need to remove unnecessary networking features, e.g. in vboot.

@leongross leongross requested a review from a team as a code owner August 1, 2024 09:39
@leongross leongross requested a review from rminnich August 21, 2024 18:49
@leongross leongross changed the title tpmutil: seperate OpenTPM into emulion and non-emulation via build tag tpmutil: separate OpenTPM into emulion and non-emulation via build tag Aug 22, 2024
to prohibit the inclusion of netowrk packages seperate the build of
tpmutil via buildtag 'emu' into a filesystem based and a socket based
version.

Signed-off-by: leongross <leon.gross@9elements.com>
@chrisfenner
Copy link
Member

Hi @leongross, first my apologies for slow SLO on PR review here.

I confess, I don't really understand the purpose of this change. What aspect of go-tpm is pulling in net in your use case? I feel like a build tag that disables some compilation is less ideal than just factoring packages better.

@leongross
Copy link
Author

leongross commented Aug 27, 2024

I dug up this "problem" while enabling builds of u-root commands using tinygo.
Tinygo does not (yet) support networking on linux systems, s.t. APIs like net.Dial cannot be used. While building the before mentioned vboot command the build failed and I investigated, that this was due to this go-tpm package requiring the net package.

The function OpenTPM checks the type of the TPM (linux device aka file, or Unix Domain Socket for emulation) at runtime. Hence there is no way to build this package depending on if the type of supported TPM interface (emulation or non-emulation) is known and should be set at build time.

I want to move this decision of the opening mode from runtime to build time.
There could even be something like only file-based, only uds-based, and as is, decide at the runtime, so every use case is covered.

An alternative to build-tags might be several OpenTPM functions so that the dead code elimination could take care of keeping the net package out of the way.

func OpenTPM(path string) (io.ReadWriteCloser, error)       // old API for runtime decision
func OpenTPMFile(path string) (io.ReadWriteCloser, error)
func OpenTPMUds(path string) (io.ReadWriteCloser, error)

EDIT: I tried to split this up as said https://github.com/leongross/go-tpm/tree/ref/emulator-dce but it does not work as expected, tinygo does not pick the dce up and the build fails. It seems as the initially proposed refactoring is the only working solution.

@chrisfenner

@leongross leongross changed the title tpmutil: separate OpenTPM into emulion and non-emulation via build tag tpmutil: separate OpenTPM into emulion and non-emulation Aug 27, 2024
@leongross
Copy link
Author

any feedback on my proposals? @chrisfenner @rminnich @josephlr

@leongross
Copy link
Author

@chrisfenner @rminnich @josephlr any thoughts on that?

@chrisfenner
Copy link
Member

Agh, sorry for the delay @leongross. Let me try to find some time to take a look this week. I need to tinker with this to fully understand why the DCE can't help us yet...

@leongross leongross changed the title tpmutil: separate OpenTPM into emulion and non-emulation tpmutil: separate OpenTPM into emulation and non-emulation Sep 9, 2024
@chrisfenner
Copy link
Member

First off, sorry for the extensive delays here. We've had trouble with our CI in this repo, and I've been busy with my day-to-day work.

I'm hesitant to add a(nother) build tag here, but I see the problem you're running into.

  1. We have this pretty awkward OpenTPM stack, even for the new AP:

    tpmutil's OpenTPM performs a run-time check of the file mode flags to decide whether to use net.Dial to open the UDS, or just open the file. Thus, the dead code eliminator cannot delete either path.

  2. Regardless of whether you are using the legacy or the new API, calling tpmutil directly or not, you're affected. Also this call stack is weird.

  3. I don't prefer adding a(nother) build tag here because it really just bandaids the problem you're having.

  4. Making any change to transport.OpenTPM will probably break someone.

Here's my suggestion, @leongross please let me know what you think.

Let's add some new transport packages under tpm2/transport, one for each type of TPM someone might want to connect to (Linux device file, Linux UDS, Windows, TCP). This requires the caller to be very explicit about which TPM they want to use, rather than relying on some heuristic under the hood and linking to everything.

Normally I'd suggest that you make this change to unblock yourself, but I'm not willing to make that suggestion after taking 6 weeks to really get to this PR, it's not fair to you. So, I will send a PR and add you as a reviewer.

@leongross
Copy link
Author

@chrisfenner thank you for your extensive explanation and the work you are putting in here.
The architectural change you proposed for the transport packages makes a lot of sense looking at its current state. Making the transport type explicit the entire stack down should solve the problem. As soon as you have something worked out, I will review it as quickly as possible.

chrisfenner added a commit to chrisfenner/go-tpm that referenced this pull request Sep 18, 2024
google#364 called to attention some
long-standing technical debt around TPM transport. In particular, the
stack looks like:

(Linux or Windows) `OpenTPM` function
calls the legacy `OpenTPM` function
calls the tpmutil `OpenTPM` function

At the bottom of the stack, tpmutil does some runtime introspection to
see what type of TPM it wants to open (e.g., on Linux, the device could
be either a device file or a socket). This runtime support is
convenient, but also breaks dead-code elimination (for example, tinygo
will fail to compile the UDS support code, and users have no way of
leaving that out without patches).

In principle, we've found within Google that "open my TPM" should be as
un-smart as possible, to avoid awkward edge cases (for example, what
happens if the logic finds two different TPMs on the system; which
should it prefer; should it invisibly succeed and surprise the user?).
Instead, the preferred pattern is to require the user to explicitly say
which TPM they are trying to open.

This change introduces 3 packages as a replacement for
`transport.OpenTPM` (which this change marks as now Deprecated):

`transport/linuxtpm.Open(path)` opens Linux device TPMs (e.g., /dev/tpm0 or
/dev/tpmrm0)
`transport/linuxudstpm.Open(path)` opens Linux Unix Domain Socket TPMs
`transport/windowstpm.Open()` opens the TPM from TBS.dll

Intentionally, the now-deprecated `transport.OpenTPM` is not touched.
This would create an import cycle.
@chrisfenner
Copy link
Member

I sent #369, PTAL @leongross. I'd especially like to know if tinygo happily compiles a program that uses linuxtpm.Open :)

@leongross
Copy link
Author

I will have a look at it @chrisfenner.

@leongross
Copy link
Author

This PR can be closed since #369 implemented all the necessary changes.

@leongross leongross closed this Sep 19, 2024
chrisfenner added a commit that referenced this pull request Sep 19, 2024
* Create individual packages for Windows and Linux TPM transport

#364 called to attention some
long-standing technical debt around TPM transport. In particular, the
stack looks like:

(Linux or Windows) `OpenTPM` function
calls the legacy `OpenTPM` function
calls the tpmutil `OpenTPM` function

At the bottom of the stack, tpmutil does some runtime introspection to
see what type of TPM it wants to open (e.g., on Linux, the device could
be either a device file or a socket). This runtime support is
convenient, but also breaks dead-code elimination (for example, tinygo
will fail to compile the UDS support code, and users have no way of
leaving that out without patches).

In principle, we've found within Google that "open my TPM" should be as
un-smart as possible, to avoid awkward edge cases (for example, what
happens if the logic finds two different TPMs on the system; which
should it prefer; should it invisibly succeed and surprise the user?).
Instead, the preferred pattern is to require the user to explicitly say
which TPM they are trying to open.

This change introduces 3 packages as a replacement for
`transport.OpenTPM` (which this change marks as now Deprecated):

`transport/linuxtpm.Open(path)` opens Linux device TPMs (e.g., /dev/tpm0 or
/dev/tpmrm0)
`transport/linuxudstpm.Open(path)` opens Linux Unix Domain Socket TPMs
`transport/windowstpm.Open()` opens the TPM from TBS.dll

Intentionally, the now-deprecated `transport.OpenTPM` is not touched.
This would create an import cycle.

* Add small tests for each of the openers

* fix lint

* fix linuxudstpm and test

* fix the test in the case that the UDS simulator is not running

* remove extraneous test for windows
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.

3 participants