New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 891994 link

Starred by 1 user

Issue metadata

Status: Untriaged
Owner: ----
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: ----
Pri: 2
Type: Bug



Sign in to add a comment

ps8751 TCPC software sync doesn't detect if a firmware update was interrupted

Project Member Reported by jwer...@chromium.org, Oct 4

Issue description

Looks like we don't do any real integrity check for the ps8751 aux firmware. I had a firmware update interrupted near the very end due to a driver bug on my Cheza, and on the next boot vboot just happily assumed that I was running the new image. The only thing we do to check an image is query the version number from the TCPC -- if we wrote enough of the image to get the TCPC basically running, it will return the right value there, but there's no guarantee that there's no more subtle corruption in the latter parts. (Maybe Parade has some sort of internal integrity check, but at least it doesn't seem to cover the whole file we write.)

Fixing this is tricky, because we can't check the whole image for speed reasons. But we can build upon the knowledge of how we flash: first we erase the whole thing, then we keep writing bytes from front to back. So if we verify that the last byte was written correctly, that should be enough to prove that the update was not interrupted.

The check_hash() function that does the version check doesn't have access to the whole firmware image and size (which we don't want to load from SPI for speed reasons unless we actually update). It just gets the contents of the ps8751_a3.hash file, which is not actually a hash but just contains the raw version number we match. So my suggestion would be that the ebuild would search the image for the last non-0xff byte in it (because 0xff is indistinguishable from erased flash), and that record both the offset and value of that byte in the ps8751_a3.hash file next to the version number. Then we can check that on every boot as part of check_hash().

We also have the problem that we would need to go through the whole "suspend EC use of the bus and put the TCPC into flash pass-through mode" setup dance every time we want to do this, which we can currently avoid when we just want to check the version (because we ask the EC which has already read it). On a warm reboot, that bus should still be locked down for pass-through on the EC anyway... in that case we know that the TCPC couldn't possibly have been incompletely updated on the last boot (because then depthcharge dies and doesn't lock down the bus first), so we can just return success right away. The larger cost would only be added on a cold boot.

Thoughts and potential takers?
 
This will probably show my ignorance of the system:

Is there a non-volatile place we could write to when we started a firmware update and cleared when we successfully verified the update? We wouldn't have to lock down the EC i2c tunnel every time.
Yes, we could store a flag in vboot NVRAM, but I feel like that wouldn't fit that cleanly into our architecture. vboot doesn't have knowledge of each individual TCPC, so we'd have to store one bit for all of them (or majorly rearrange something else, or hack in a layering violation). That means it would have to force-update all TCPCs again if the update for one of them failed (and I'm not even sure how well the others like ANX would react to updating the same image again). Also, vboot NVRAM is not trusted so malicious userspace could keep forcing you to update your TCPCs to wear out the flash or something like that. (I guess we could also put it in a TPM space which can be locked down, but that would be even more complicated to pipe in there. I think it would be nice to have a solution that is limited to the ps8751 driver.)

Sign in to add a comment