Two Out-of-Bounds Access Vulnerabilities in TPM 2.0 Reference Implementation

We discussed this vulnerability during Episode 196 on 14 March 2023

Two vulnerabilities in the TPM 2.0 reference implementation’s CryptParameterDecryption(). The Trusted Platform Module (TPM) is used for key storage, key generation, and attestation via storing and taking “measurements” (integrity checks) in the boot process. As it’s doing sensitive actions, some commands like to have their parameters encrypted before going across the bus to the TPM. To handle this, the TPM facilitates “session-based encryption”, where you can establish a session and pass the session data in the command, and the TPM will have the session info to decrypt the parameters. As part of that though, the user provides a cipherSize and some other cipher-related data that follows it.

The first problem is that the system does not validate that the incoming command buffer is actually large enough to contain a parameterArea. The system will attempt to read a 15-bit value from the start of this area, In the case where there is no parameterArea in the buffer, this read will be 2bytes outside of the bounds of the command buffer. The impact of this 2-byte out-of-bounds read depends on the TPM user. On some targets, such as Hyper-V, the command buffer is a fixed size, and the unused bytes are zeroed out before being processed by the TPM, so the read will always be zero. If a platform does not zero out the command buffer, then it is possible that the read will get a stale value at that position, potentially leading to a more significant corruption as it tried to decrypt the stale data in-place.

The other problem is an out-of-bounds write due to a logic bug when checking the cipherSize. They try to ensure the cipherSize < sizeof(buffer), but since the size is encoded into the first two bytes of the buffer, they advance the buffer pointer by two bytes to get to the cipher data. However, they don’t take that into account when checking the cipherSize, and thus it’s possible to get a 2 byte OOB write. Again, how useful this is depends on the target. On VMware for example, a much larger buffer (0x10000) than the max TPM command size is used and as such, this bug is probably not useful there. Hyper-V on the other hand will allocate a static sized buffer which is exactly the max TPM command size (0x1000).