Skip to content
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

[WIP WIP WIP] Allow loading images that were embedded as sections inside a previously verified image #740

Closed
wants to merge 1 commit into from

Conversation

kukrimate
Copy link
Contributor

I have realised that the hashes cannot be stored inside loaded images because it would break old grubs that call shim_lock->verify() on a UKI and run it without loader proto.

Instead I create a global list of hashes of all sections of all images that were verified.

Then if someone tries to later verify an image that was previously hashed as a section, they get to pass.

Please note that this is WIP, and untested code, and was written in 30 minutes, but it should be a starting point.

@kukrimate
Copy link
Contributor Author

WARNING: this is likely not secure.

The attack I have in mind is:

  • I load UKI in GRUB, but not run it. This will add the embedded kernel to allowlist.
  • Then I load embedded kernel separately in GRUB, and I can lunch it with an arbitrary command line and initrd, defeating the purpose of the UKI.

Only way to fix this would be to restrict the allowlist to current running image's sections, but that wouldn't work with existing GRUBs that don't use the loader protocol.

So I believe the only way to solve the regression with existing artefacts is to not hook the system table after all.

@kukrimate kukrimate closed this Mar 26, 2025
@bluca
Copy link
Contributor

bluca commented Mar 26, 2025

So I believe the only way to solve the regression with existing artefacts is to not hook the system table after all.

But that's still affected by the same case though? Because it would mean having to sign the inner kernel. But that means you can also just extract it and run it with an arbitrary initrd/cmdline combination.

@ardbiesheuvel
Copy link
Contributor

WARNING: this is likely not secure.

The attack I have in mind is:

  • I load UKI in GRUB, but not run it. This will add the embedded kernel to allowlist.

That just means that the allowlist should be augmented at StartImage() time, not before, and wiped again when the image returns.

@kukrimate
Copy link
Contributor Author

@ardbiesheuvel

That just means that the allowlist should be augmented at StartImage() time, not before, and wiped again when the image returns.

I don't think that will work, because existing artifacts that only call into shim to do verify(), and start the image using their own mechanism, which means shim doesnt really know which image is really running

@bluca
Copy link
Contributor

bluca commented Mar 27, 2025

That's not the case? StartImage is used. There is a corner case with old kernels where the old efi handover protocol is used instead, but that's very much on the way out

@ardbiesheuvel
Copy link
Contributor

@ardbiesheuvel

That just means that the allowlist should be augmented at StartImage() time, not before, and wiped again when the image returns.

I don't think that will work, because existing artifacts that only call into shim to do verify(), and start the image using their own mechanism, which means shim doesnt really know which image is really running

If shim's startimage is not used, we don't need this trick, right? And if it is used, it will be exposed via the loader protocol and hooked into the system table, and starting the uki image should always return via startimage, even when doing a longjmp from the exit boot service.

@ardbiesheuvel
Copy link
Contributor

And if UKI currently passes the parent image handle correctly when loading the inner kernel, we could limit this to sections of the direct parent, rather than have a global view to which hashes are added and removed.

@kukrimate
Copy link
Contributor Author

That's not the case? StartImage is used. There is a corner case with old kernels where the old efi handover protocol is used instead, but that's very much on the way out

@bluca Yes the stub itself does that, but if the loader that loaded the stub, didnt call StartImage() when starting it, shim simply does not know the stub is running.
This is the case for our current use case with GRUB+peimage in ubuntu.

If shim's startimage is not used, we don't need this trick, right? And if it is used, it will be exposed via the loader protocol and hooked into the system table, and starting the uki image should always return via startimage, even when doing a longjmp from the exit boot service.

@ardbiesheuvel well the problem is it's sort of used, the stub uses start image, but some bootloaders that start the stub itself (such as grub) might not, which means shim does not always know when the stub is started, even if it was used to verify it.

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