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

vmsa: Updating for kernel debug_swap #32

Merged
merged 1 commit into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ $ sev-snp-measure --help
usage: sev-snp-measure [-h] [--version] [-v] --mode {sev,seves,snp,snp:ovmf-hash,snp:svsm}
[--vcpus N] [--vcpu-type CPUTYPE] [--vcpu-sig VALUE] [--vcpu-family FAMILY]
[--vcpu-model MODEL] [--vcpu-stepping STEPPING] [--vmm-type VMMTYPE] --ovmf
PATH [--kernel PATH] [--initrd PATH] [--append CMDLINE]
PATH [--kernel PATH] [--initrd PATH] [--append CMDLINE] [--guest-features VALUE]
[--output-format {hex,base64}] [--snp-ovmf-hash HASH] [--dump-vmsa]
[--vars-size VARS_SIZE] [--svsm SVSM]

Expand All @@ -58,6 +58,9 @@ options:
--kernel PATH Kernel file to calculate hash from
--initrd PATH Initrd file to calculate hash from (use with --kernel)
--append CMDLINE Kernel command line to calculate hash from (use with --kernel)


--guest-features Hex representation of the guest kernel features expected to be included (defaults to 0x21); see README.md for possible values.
--output-format {hex,base64}
Measurement output format
--snp-ovmf-hash HASH Precalculated hash of the OVMF binary (hex string)
Expand Down Expand Up @@ -97,7 +100,7 @@ from sevsnpmeasure import vcpu_types
from sevsnpmeasure.sev_mode import SevMode

ld = guest.calc_launch_digest(SevMode.SEV_SNP, vcpus_num, vcpu_types.CPU_SIGS["EPYC-v4"],
ovmf_path, kernel_path, initrd_path, cmdline_str)
ovmf_path, kernel_path, initrd_path, cmdline_str, guest_features)
print("Calculated measurement:", ld.hex())

block = id_block.snp_calc_id_block(ld,"id_key_file","author_key_file")
Expand All @@ -119,6 +122,30 @@ example, the following 3 invocations are identical:
2. `sev-snp-measure --vcpu-sig=0x800f12 ...`
3. `sev-snp-measure --vcpu-family=23 --vcpu-model=1 --vcpu-stepping=2 ...`

## SEV-SNP Guest Feature Field Values
Prior to Linux Kernel version 6.6, the default value was always calculated to `0x1`, as the kernel only supported `SNPActive`. After the release of Linux Kernel 6.6, additional features were made available some of them enabled by default. Because of this, the new default value is `0x21` which is `SNPActive + DebugSwap`. Other possible combinations my be derived by generating a 64-bit hex value from the following chart:

| BIT FIELD | Description |
|:---------:|:------------:|
| 0 | SNPActive |
| 1 | vTOM |
| 2 | ReflectVC |
| 3 | RestrictedInjection |
| 4 | AlternateInjection |
| 5 | DebugSwap |
| 6 | PreventHostIBS |
| 7 | BTBIsolation |
| 8 | VmplSSS |
| 9 | SecureTSC |
| 10 | VmgexitParameter |
| 11 | Reserved, SBZ |
| 12 | IbsVirtualization |
| 13 | Reserved, SBZ |
| 14 | VmsaRegProt |
| 15 | SmtProtection |
| 63:16 | Reserved, SBZ |


## Precalculated OVMF hashes

The SEV-SNP digest gets generated in multiple steps that each have a digest as output. With that digest output, you can stop at any of these steps and continue generation of the full digest later. These are the steps:
Expand Down
7 changes: 6 additions & 1 deletion sevsnpmeasure/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ def main() -> int:
help='Initrd file to calculate hash from (use with --kernel)')
parser.add_argument('--append', metavar='CMDLINE',
help='Kernel command line to calculate hash from (use with --kernel)')
parser.add_argument('--guest-features', metavar='VALUE', type=lambda x: int(x, 0),
default=0x21,
help="Hex representation of the guest kernel features expected to be included "
"(defaults to 0x21); see README.md for possible values"),
parser.add_argument('--output-format', choices=['hex', 'base64'], help='Measurement output format', default='hex')
parser.add_argument('--snp-ovmf-hash', metavar='HASH', help='Precalculated hash of the OVMF binary (hex string)')
parser.add_argument('--dump-vmsa', action='store_true',
Expand Down Expand Up @@ -104,7 +108,8 @@ def main() -> int:
parser.error("--dump-vmsa is not availibe in the selected mode")

ld = guest.calc_launch_digest(sev_mode, args.vcpus, vcpu_sig, args.ovmf, args.kernel, args.initrd, args.append,
args.snp_ovmf_hash, vmm_type, args.dump_vmsa, args.svsm, args.vars_size)
args.guest_features, args.snp_ovmf_hash, vmm_type, args.dump_vmsa,
args.svsm, args.vars_size)

print_measurement(ld, sev_mode, args.output_format, args.verbose)
except RuntimeError as e:
Expand Down
18 changes: 9 additions & 9 deletions sevsnpmeasure/guest.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@


def calc_launch_digest(mode: SevMode, vcpus: int, vcpu_sig: int, ovmf_file: str,
kernel: str, initrd: str, append: str, snp_ovmf_hash_str: str = '',
kernel: str, initrd: str, append: str, guest_features: int, snp_ovmf_hash_str: str = '',
vmm_type: VMMType = VMMType.QEMU, dump_vmsa: bool = False, svsm_file: str = '',
ovmf_vars_size: int = 0) -> bytes:
if snp_ovmf_hash_str and mode != SevMode.SEV_SNP:
raise ValueError("SNP OVMF hash only works with SNP")

if mode == SevMode.SEV_SNP:
return snp_calc_launch_digest(vcpus, vcpu_sig, ovmf_file, kernel, initrd, append, snp_ovmf_hash_str, vmm_type,
dump_vmsa=dump_vmsa)
return snp_calc_launch_digest(vcpus, vcpu_sig, ovmf_file, kernel, initrd, append, guest_features,
snp_ovmf_hash_str, vmm_type, dump_vmsa=dump_vmsa)
elif mode == SevMode.SEV_ES:
return seves_calc_launch_digest(vcpus, vcpu_sig, ovmf_file, kernel, initrd, append, vmm_type=vmm_type,
dump_vmsa=dump_vmsa)
return seves_calc_launch_digest(vcpus, vcpu_sig, ovmf_file, kernel, initrd, append,
vmm_type=vmm_type, dump_vmsa=dump_vmsa)
elif mode == SevMode.SEV:
return sev_calc_launch_digest(ovmf_file, kernel, initrd, append)
elif mode == SevMode.SEV_SNP_SVSM:
Expand Down Expand Up @@ -88,8 +88,8 @@ def calc_snp_ovmf_hash(ovmf_file: str) -> bytes:


def snp_calc_launch_digest(vcpus: int, vcpu_sig: int, ovmf_file: str,
kernel: str, initrd: str, append: str, ovmf_hash_str: str,
vmm_type: VMMType = VMMType.QEMU, dump_vmsa: bool = False) -> bytes:
kernel: str, initrd: str, append: str, guest_features: int,
ovmf_hash_str: str, vmm_type: VMMType = VMMType.QEMU, dump_vmsa: bool = False) -> bytes:

gctx = GCTX()
ovmf = OVMF(ovmf_file)
Expand All @@ -108,7 +108,7 @@ def snp_calc_launch_digest(vcpus: int, vcpu_sig: int, ovmf_file: str,

snp_update_metadata_pages(gctx, ovmf, sev_hashes, vmm_type)

vmsa = VMSA(SevMode.SEV_SNP, ovmf.sev_es_reset_eip(), vcpu_sig, vmm_type)
vmsa = VMSA(SevMode.SEV_SNP, ovmf.sev_es_reset_eip(), vcpu_sig, guest_features, vmm_type)
for i, vmsa_page in enumerate(vmsa.pages(vcpus)):
gctx.update_vmsa_page(vmsa_page)
if dump_vmsa:
Expand Down Expand Up @@ -149,7 +149,7 @@ def seves_calc_launch_digest(vcpus: int, vcpu_sig: int, ovmf_file: str, kernel:
raise RuntimeError("Kernel specified but OVMF doesn't support kernel/initrd/cmdline measurement")
sev_hashes_table = SevHashes(kernel, initrd, append).construct_table()
launch_hash.update(sev_hashes_table)
vmsa = VMSA(SevMode.SEV_ES, ovmf.sev_es_reset_eip(), vcpu_sig, vmm_type)
vmsa = VMSA(SevMode.SEV_ES, ovmf.sev_es_reset_eip(), vcpu_sig, 0x0, vmm_type)
for i, vmsa_page in enumerate(vmsa.pages(vcpus)):
launch_hash.update(vmsa_page)
if dump_vmsa:
Expand Down
12 changes: 4 additions & 8 deletions sevsnpmeasure/vmsa.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,15 +182,11 @@ def build_save_area(eip: int, sev_features: int, vcpu_sig: int, vmm_type: VMMTyp
xcr0=0x1,
)

def __init__(self, sev_mode: SevMode, ap_eip: int, vcpu_sig: int, vmm_type: VMMType = VMMType.QEMU):
if sev_mode == SevMode.SEV_SNP:
sev_features = 0x1
else:
sev_features = 0x0

self.bsp_save_area = VMSA.build_save_area(self.BSP_EIP, sev_features, vcpu_sig, vmm_type)
def __init__(self, sev_mode: SevMode, ap_eip: int, vcpu_sig: int, guest_features: int,
vmm_type: VMMType = VMMType.QEMU):
self.bsp_save_area = VMSA.build_save_area(self.BSP_EIP, guest_features, vcpu_sig, vmm_type)
if ap_eip:
self.ap_save_area = VMSA.build_save_area(ap_eip, sev_features, vcpu_sig, vmm_type)
self.ap_save_area = VMSA.build_save_area(ap_eip, guest_features, vcpu_sig, vmm_type)

def pages(self, vcpus: int) -> Iterator[bytes]:
"""
Expand Down
Loading
Loading