-
-
Notifications
You must be signed in to change notification settings - Fork 187
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
Introduce io386 to heads and use it to finalize chipset at runtime #326
Conversation
512dfdf
to
1684ab4
Compare
On some newer platforms of intel (confirmed on nehalem, sandy/ivy bridge), coreboot after commit [2ac149d294af795710eb4bb20f093e9920604abd](https://review.coreboot.org/cgit/coreboot.git/commit/?id=2ac149d294af795710eb4bb20f093e9920604abd) registers an SMI to lockdown some registers on the chipset, as well as access to the SPI flash, optionally. The SMI will always be triggered by coreboot during S3 resume, but can be triggered by either coreboot or the payload during normal boot path. Enabling lockdown access to SPI flash will effectly write-protect it, but there is no runtime option for coreboot to control it, so letting coreboot to trigger such SMI will leave the owner of the machine lost any possibility to program the SPI flash with its own OS, and becomes a nightmare if the machine is uneasy to disassemble, so a scheme could be implement, in which the SMI to lockdown chipset and SPI flash is left for a payload to trigger, and temporarily disabling such triggering in order to program the SPI flash needs authentication. I have implemented a passcode-protected runtime-disableable lockdown with grub, described [here](https://github.com/hardenedlinux/Debian-GNU-Linux-Profiles/blob/master/docs/hardened_boot/grub-for-coreboot.md#update-for-coreboot-after-commit-2ac149d294af795710eb4bb20f093e9920604abd). In order to implement a similar scheme for Heads, I wrote [io386](https://github.com/hardenedlinux/io386). With this commit, io386 will be called before entering boot routine to trigger the SMI to finalize the chipset and write protect the SPI flash at the same time. Entering recovery shell will leave the flash writable. (The authentication routine implemented in previous revisions has been split as an independent commit.)
This seems like a generally useful sort of tool. What do you think about merging the io386 and flashtools trees? They have some overlap (flashtools provides |
I follow the Unix philosophy to do one thing and do it well. Your flashtools is a simplified flashrom, while hardenedlinux's io386 is a tool dedicated for I/O operations. I do not believe that they should be merged. |
Thanks for writing this! I guess we'll need something like this sooner or later. Could you link to datasheets or docs you used? Where does 0x2b and 0xcb come from? What exactly does coreboot's LOCK_SPI_FLASH_RO differently or not? thanks! ps. IMO it would make sense to add io386 or something similar to the flashtools repo. |
I did these by imitating what coreboot does.
They are inside src/include/cpu/x86/smm.h of coreboot source tree. You can see
Setting LOCK_SPI_FLASH_RO will lock the SPI flash BEFORE any payload is called, so one have no way even to disable the locking temporarily at runtime (but locking done with grub or heads can be disabled at runtime allowing the owner to (re) program the SPI flash in-system, and one can write codes for authentication to protect it from unauthorized access). On platforms whose SPI flash is hard to access (e.g. accessing the flash needs to tear down the whole machine), setting an SPI lock impossible to disable at runtime will be a nightmare to update their firmware. |
good. thanks.
what do you mean by "locking in heads (using io386?) can be disabled at runtime"? That seems different to what coreboot does(?). I guess what we need is a irrevesable one-time write-protection that is off at power-on. maybe I got you wrong though..
We configure coreboot not to "finalize"/"write-protect" the SPI flash and do it ourselves, (at least) just before we kexec away on disc. That way we have all our flashrom upgrade functions in Heads available, and no need to disassemble, right? |
It is the same as what coreboot does, and locking in heads (using io386?) can indeed be disabled at runtime by not to call the io386 itself, as long as the wrapping scripts allows it.
That at least is a way to make things easier.
It is a policy, not a mechanism, while leaving the flash temporarily unlocked is a mechanism. With it, the owner can choose to kexec into the OS ,or even chroot to the rootfs on disk to update the firmware, not limited to your "flashrom upgrade functions in Heads" stuff. |
thanks. yes, that's policy, and I think we can leave that an open issue in Heads. Denying anything else than Heads (still the user) to write, helps and is a good start. TPM measurements won't succeed after changes in flash anyways, and we can come up with more, later. |
Did a first test of this by just calling lock_chip somewhere in the (gui) menu before I boot, but nothing really changed: I could reprogram the flash (flashrom -p internal) just like before. has anyone else tested this? |
@merge |
@merge These settings does not take effect until the SMI is triggered via outb(0x2b, 0xcb), either by coreboot itself (if INTEL_CHIPSET_LOCKDOWN=y) or by later stages. |
Is this something which could be repurposed to add more general write-protect support to Flashrom? |
EDIT: tested and works! Changes to streamline this PR (and make it effective into both generic-init and gui-init with reduced required changes and maintenance in future):
Here is the patch on top of #1015 (will test later):
@MrChromebox : this was one of the blocker to #836, which if combined with a proper authentication prior of accessing recovery shell, could be merged. tlaurion@3343f8d PoC for x230-hotp-maximized shows that only Heads would be able to flash ROM. The other one being a proper recovery shell authentication mechanism #881's implementation, which #361 implements correctly but leaves the user locked out if his public key expired. Discussion: #881 (comment) |
@tlaurion I like where this is going, and a quick perusal of coreboot's code seems to indicate this should work properly on newer platforms as well. So we just need to figure out the Recovery Shell piece |
@MrChromebox tagged you under #881 |
@tlaurion |
@MrChromebox You can test functionality easily from recovery by: . /etc/functions Having it undefined lets the payload responsible to lock it, which is what io386 does here. Unless you say that the behavior changed in coreboot 4.14+ from your tests? |
I'm saying you don't want |
@MrChromebox so basically, just having lockdown not set should do it. 4.15 locks it by default. Will retest |
@MrChromebox: rempoving
succeeds. On 4.13 Calling
Can try to test newer coreboot versions.... |
@tlaurion what version of coreboot are you testing against? in 4.14+, BOOTMEDIA_LOCK_CONTROLLER is used in boot_device_security_lockdown() in lockdown.c, which is called not by SMM, but before resource assignment in ramstage edit: this looks to be the case for 4.13 too. So I'm not sure how you're able to enable this and still update via Heads, because it will already have been locked. the lock_chip() function is making an SMM call, that's completely separate |
@MrChromebox this was on top #1015 (coreboot 4.13) |
@MrChromebox : Having both chipset_lockdown unset and boot_media_lock_controller set: Without calling lock_chip, Flashing ROMCalling lock_chip, then reflashing the same ROM (notice warning of locked regions)Then attempting to flash new ROM, which fails |
Having chipset_lockdown unset but without boot_media_lock_controller set lock_chip does nothing and permit flashing prior and after the call. |
@tlaurion then this is a highly platform-specific solution then, likely only works on Sandy/Ivy. On the L14, if BOOTMEDIA_LOCK_CONTROLLER is set, then nothing is flashable regardless if lock_chip has been called or not. I had to externally flash to clear it |
Hmmm.
When removing |
then I need to take a closer look at the SNB/IVB code to see why it's different there vs SKL and newer |
@MrChromebox any input here on how it is supposed to be for other platforms? |
@tlaurion it's simply not going to work on newer platforms where FSP locks those registers regardless of any coreboot settings. They simply can't be set by the payload, even in SMM. CONFIG_INTEL_CHIPSET_LOCKDOWN has no effect on Skylake and newer. |
@MrChromebox here are the changes applied on top of 3343f8d with make savedfeconfig for coreboot config with SMI debug on:
Where coreboot long config diff (as opposed to defconfig diff above) looks like this as a patch:
|
@MrChromebox : I added SMI debug from above config. What exactly do you want me to add to config and then what exactly do you want me to dump here? |
@tlaurion I'm honestly not sure. I guess I need to take another / more in depth look at coreboot to try and understand the execution flow that's allowing this to work on SNB/IVB |
ok, looked at this more closely (and beat my x230 into submission enough to do some testing), and seems that on SNB (Sandy bridge)/IVB (Ivy bridge), setting the FPR alone (which boot_device_security_lockdown() does in ramstage) is not sufficient to prevent writes to flash. The chipset finalization is required as well, which is what But, on newer FSP_based platforms (SKL+), FSP will perform the chipset finalization functions (at least w/r/t the flash protection registers) if coreboot does not, so there is no opportunity for the payload to do it. So, this approach works, but not for any 6th-gen or newer devices |
Considering io386 is an interesting security improvement for xx20 and xx30 boards, since OS cannot touch SPI in write mode even if
|
This feature alone, per previous post referred PR, just works for xx30/xx20 on coreboot 4.13+ and mitigates a platora of attacks from OS targeting firmware modifications. But it does not prevent, without recovery shell authentication a local attacker to get to recovery shell, backup ROM, tamper ROM and flash back a ROM faking measurements without being noticed. Maybe we should give option to user to use TPM disk unlock key (sufficient)/GPG user pin(limited)/LUKS Disk recovery Key passphrase(not so great idea, disk swap would be sufficient to authenticate) when going to recovery shell and for upgrading firmware (not so needed: read below)? Each option has it's risks and limitations, but one is at least needed here to implement this feature while making it truely useful. But merging this first while deciding of the best authenticating mechanisms are totally different issues. The blocker here is really just how to authenticate user in case of access to recovery shell and how to properly handle firmware upgrade from heads... Out of ideas outside of the followings. Otherwise, this would give advantage to sandy/ivy for locking correctly platform access to SPI flash, preventing at least the OS to be able to modify the firmware whatsoever (iomem=relaxed not working anymore). But that is void if user can just go to recovery shell to backup current whole ROM, thinker leisure and then come back at machine to flash a ROM which would contain hardcoded values of past valid ROM measurements including user's public key, user config files and tampered binaries and scripts... So authentication is mandatory to at least limit access to the recovery shell to backup/extract/tamper firmware and flash it back unnoticed. Disk recovery key passphrase alone (luksOpen check) would be susceptible to disk swap and is not good enough to truly authenticate user, while physical access would be needed here to swap disks. I would go against that. Disk Unlock key is a feature limited to non-Librems and could fit the bill since this PR is targeting only sandy/ivy bridges as of now, while access to recovery shell unauthorized is jeopardizing security of all boards for other threats, including users just wanting to nuke OS from it.... GPG user PIN would need to have workaround for expired keys and when a key is not existing, while needing fallback of some sort to other mechanisms, which are lacking in case of lost USB Security dongle to be able to use GPG User PIN as a mechanism alone for authentication for recovery shell, while not really a problem if flashing from Heads menu is permitted, permitting user to flash a fresh ROM without key and generating a new one on next boot. We could simply protect recovery access while ROM flashing would still be permitted as a mitigation, but where attackers would be in the dark if not possible to access recovery shell to get a proper ROM backup to craft a tampered one faking measurements. So in my opinion, preventing recovery shell access might be enough. To me, the problem missing thinking is how to authenticate user in case of lost USB Security dongle, which should be first way to authenticate with some kind of fallback, while user flashing new ROM without key might mitigate this. If we are OK pushing this feature with Disk Unlock Key as fallback for GPG User PIN for xx30 and xx20, then there is no problem. In that case, the TPM release of the Disk Unlock key as authentication would be the strongest authentication ( #1091 now measuring whole LUKS headers into TPM NVRAM to seal/unseal Disk Unlock Key, while #1093 is giving insights of why Disk Unlock Key would fail to be released). The TPM Disk Unlock Key passhphrase release would fail as an authentication mechanism in case of a disk swap here, and wound prove the firmware state, cbfs files state, normal boot patch, kernel modules state being the same as when state was sealed, as opposed to GPG User PIN which would only validate that the USB Security dongle is connected with someone knowing the PIN, no other states are validated, which is enough for some use cases. If the user or attacker decides to flash a clean ROM without conserving public key and user settings, then Heads currently asks on boot for generation of key. If disk is blank, user is asked to install from USB. Consequently, the user having lost his USB dongle could reflash a clean ROM from USB and regenerate keys. Consequently, the user could be asked to authenticate with TPM Disk Unlock Key passphrase/ GPG user PIN to access the recovery shell, while flashing a new firmware could stay unauthenticated. Otherwise I need you brains, guys. Challenge me. @Thrilleratplay? @Tonux599 @persmule? @kylerankin (not relevant to Purism but xx30/xx20 only for platform lockdown, but what about recovery shell authorized access)? @MrChromebox? |
On some newer platforms of intel (confirmed on nehalem, sandy/ivy
bridge), coreboot after commit 2ac149d294af795710eb4bb20f093e9920604abd
registers an SMI to lockdown some registers on the chipset, as well
as access to the SPI flash, optionally. The SMI will always be triggered
by coreboot during S3 resume, but can be triggered by either coreboot
or the payload during normal boot path.
Enabling lockdown access to SPI flash will effectly write-protect it,
but there is no runtime option for coreboot to control it, so letting
coreboot to trigger such SMI will leave the owner of the machine lost
any possibility to program the SPI flash with its own OS, and becomes
a nightmare if the machine is uneasy to disassemble, so a scheme could
be implement, in which the SMI to lockdown chipset and SPI flash is left
for a payload to trigger, and temporarily disabling such triggering in
order to program the SPI flash needs authentication.
I have implemented a passcode-protected runtime-disableable lockdown
with grub, described here. In order to implement a similar scheme for
Heads, I wrote io386.
With this commit, io386 will be called before entering boot routine
to trigger the SMI to finalize the chipset and write protect the SPI
flash at the same time. Entering recovery shell will leave the flash
writable.
(The authentication routine implemented in previous revisions has been
split as an independent commit.)