Intel Trust Domain Extensions(TDX)

概要

Intel の Trust Domain Extensions(TDX)は、保護ゲスト VM をホストおよび 物理攻撃から守る。CPU によるアテステーションを受けた「TDX モジュール」と 呼ばれるソフトウェアモジュールが、新しい CPU の分離領域内で動き、保護 VM (TDX ゲストまたは TD とも呼ばれる)を管理・実行する機能を提供する。

ホワイトペーパー、仕様書などの資料は [1] を参照。

本書では TDX 固有の KVM ABI を説明する。TDX モジュールは、KVM が TDX ゲ ストを実行するために使う前に初期化する必要がある。TDX モジュールを初期化 するためのサポートはホストの core カーネルが提供しており、その内容は Documentation/arch/x86/tdx.rst に書かれている。

API の説明

KVM_MEMORY_ENCRYPT_OP

Type:

vm ioctl、vcpu ioctl

TDX の操作では、KVM_MEMORY_ENCRYPT_OP は TDX 固有の sub-ioctl() コマンド を持つ汎用 ioctl として使われる。

/* Trust Domain Extensions sub-ioctl() commands. */
enum kvm_tdx_cmd_id {
        KVM_TDX_CAPABILITIES = 0,
        KVM_TDX_INIT_VM,
        KVM_TDX_INIT_VCPU,
        KVM_TDX_INIT_MEM_REGION,
        KVM_TDX_FINALIZE_VM,
        KVM_TDX_GET_CPUID,

        KVM_TDX_CMD_NR_MAX,
};

struct kvm_tdx_cmd {
      /* enum kvm_tdx_cmd_id */
      __u32 id;
      /* flags for sub-command. If sub-command doesn't use this, set zero. */
      __u32 flags;
      /*
       * data for each sub-command. An immediate or a pointer to the actual
       * data in process virtual address.  If sub-command doesn't use it,
       * set zero.
       */
      __u64 data;
      /*
       * Auxiliary error code.  The sub-command may return TDX SEAMCALL
       * status code in addition to -Exxx.
       */
      __u64 hw_error;
};

KVM_TDX_CAPABILITIES

Type:

vm ioctl

Returns:

成功時は 0、エラー時は 0 未満

システムにロードされた特定の TDX モジュールのもとで、現在の KVM が対応す る TDX ケイパビリティを返す。TDX ゲストに設定できる機能/ケイパビリティ を報告する。

  • id: KVM_TDX_CAPABILITIES

  • flags: 0 でなければならない

  • data: struct kvm_tdx_capabilities へのポインタ

  • hw_error: 0 でなければならない

struct kvm_tdx_capabilities {
      __u64 supported_attrs;
      __u64 supported_xfam;

      /* TDG.VP.VMCALL hypercalls executed in kernel and forwarded to
       * userspace, respectively
       */
      __u64 kernel_tdvmcallinfo_1_r11;
      __u64 user_tdvmcallinfo_1_r11;

      /* TDG.VP.VMCALL instruction executions subfunctions executed in kernel
       * and forwarded to userspace, respectively
       */
      __u64 kernel_tdvmcallinfo_1_r12;
      __u64 user_tdvmcallinfo_1_r12;

      __u64 reserved[250];

      /* Configurable CPUID bits for userspace */
      struct kvm_cpuid2 cpuid;
};

KVM_TDX_INIT_VM

Type:

vm ioctl

Returns:

成功時は 0、エラー時は 0 未満

TDX 固有の VM 初期化を行う。これは KVM_CREATE_VM のあと、vCPU を作成する 前に呼ぶ必要がある。

  • id: KVM_TDX_INIT_VM

  • flags: 0 でなければならない

  • data: struct kvm_tdx_init_vm へのポインタ

  • hw_error: 0 でなければならない

struct kvm_tdx_init_vm {
        __u64 attributes;
        __u64 xfam;
        __u64 mrconfigid[6];          /* sha384 digest */
        __u64 mrowner[6];             /* sha384 digest */
        __u64 mrownerconfig[6];       /* sha384 digest */

        /* The total space for TD_PARAMS before the CPUIDs is 256 bytes */
        __u64 reserved[12];

      /*
       * Call KVM_TDX_INIT_VM before vcpu creation, thus before
       * KVM_SET_CPUID2.
       * This configuration supersedes KVM_SET_CPUID2s for VCPUs because the
       * TDX module directly virtualizes those CPUIDs without VMM.  The user
       * space VMM, e.g. qemu, should make KVM_SET_CPUID2 consistent with
       * those values.  If it doesn't, KVM may have wrong idea of vCPUIDs of
       * the guest, and KVM may wrongly emulate CPUIDs or MSRs that the TDX
       * module doesn't virtualize.
       */
        struct kvm_cpuid2 cpuid;
};

KVM_TDX_INIT_VCPU

Type:

vcpu ioctl

Returns:

成功時は 0、エラー時は 0 未満

TDX 固有の vCPU 初期化を行う。

  • id: KVM_TDX_INIT_VCPU

  • flags: 0 でなければならない

  • data: ゲスト TD の vCPU RCX の初期値

  • hw_error: 0 でなければならない

KVM_TDX_INIT_MEM_REGION

Type:

vcpu ioctl

Returns:

成功時は 0、エラー時は 0 未満

@source_addr から与えられたユーザ空間のデータで、@gpa から始まる @nr_pages ページ分の TDX ゲストプライベートメモリを初期化する。@source_addr は PAGE_SIZE にアラインされていなければならない。

guest_memfd のインプレース変換が有効な場合は、@source_addr に 0 を渡して 「ソースページなし」を表す。インプレース変換が有効でないか対応していない 場合は、ソースページが必要である。

なお、このサブコマンドを呼ぶ前に、範囲 [gpa, gpa + nr_pages] のメモリ属 性を private にしておく必要がある。ユーザ空間は KVM_SET_MEMORY_ATTRIBUTES で属性を設定できる。

KVM_TDX_MEASURE_MEMORY_REGION フラグを指定すると、計測も拡張される。

  • id: KVM_TDX_INIT_MEM_REGION

  • flags: 現在定義されているのは KVM_TDX_MEASURE_MEMORY_REGION だけである

  • data: struct kvm_tdx_init_mem_region へのポインタ

  • hw_error: 0 でなければならない

#define KVM_TDX_MEASURE_MEMORY_REGION   (1UL << 0)

struct kvm_tdx_init_mem_region {
        __u64 source_addr;
        __u64 gpa;
        __u64 nr_pages;
};

KVM_TDX_FINALIZE_VM

Type:

vm ioctl

Returns:

成功時は 0、エラー時は 0 未満

初期 TD の内容の計測を完了し、実行可能としてマークする。

  • id: KVM_TDX_FINALIZE_VM

  • flags: 0 でなければならない

  • data: 0 でなければならない

  • hw_error: 0 でなければならない

KVM_TDX_GET_CPUID

Type:

vcpu ioctl

Returns:

成功時は 0、エラー時は 0 未満

TDX モジュールが TD ゲスト向けに仮想化する CPUID の値を取得する。-E2BIG が返った場合、ユーザ空間はより大きなバッファを確保して再試行すべきである。 最小バッファサイズは struct kvm_cpuid2 の nent フィールドに更新される。

  • id: KVM_TDX_GET_CPUID

  • flags: 0 でなければならない

  • data: struct kvm_cpuid2 へのポインタ(in/out)

  • hw_error: 0 でなければならない(out)

struct kvm_cpuid2 {
        __u32 nent;
        __u32 padding;
        struct kvm_cpuid_entry2 entries[0];
};

struct kvm_cpuid_entry2 {
        __u32 function;
        __u32 index;
        __u32 flags;
        __u32 eax;
        __u32 ebx;
        __u32 ecx;
        __u32 edx;
        __u32 padding[3];
};

KVM TDX の作成手順

標準の KVM の手順に加えて、新しい TDX ioctl を呼ぶ必要がある。制御の流れ は次のとおりである:

  1. システム全体のケイパビリティを確認する

    • KVM_CAP_VM_TYPES: VM タイプが対応しているか、KVM_X86_TDX_VM が対応しているかを確認する。

  2. VM を作成する

    • KVM_CREATE_VM

    • KVM_TDX_CAPABILITIES: TDX ゲストを作成するための TDX ケイパビリティを問い合わせる。

    • KVM_CHECK_EXTENSION(KVM_CAP_MAX_VCPUS): VM レベルで TD が対応する最大 vCPU 数を問い合わせる(TDX にはこの点に関する独自の制限がある)。

    • KVM_SET_TSC_KHZ: ホストと異なる TSC 周波数にしたい場合に TD の TSC 周波数を設定する。これは任意である。

    • KVM_TDX_INIT_VM: TDX 固有の VM パラメータを渡す。

  3. vCPU を作成する

    • KVM_CREATE_VCPU

    • KVM_TDX_INIT_VCPU: TDX 固有の vCPU パラメータを渡す。

    • KVM_SET_CPUID2: TD の CPUID を設定する。

    • KVM_SET_MSRS: TD の MSR を設定する。

  4. 初期ゲストメモリを初期化する

    • 初期ゲストメモリの内容を用意する。

    • KVM_TDX_INIT_MEM_REGION: 初期ゲストメモリを追加する。

    • KVM_TDX_FINALIZE_VM: TDX ゲストの計測を完了する。

  5. vCPU を実行する

参照

https://www.intel.com/content/www/us/en/developer/tools/trust-domain-extensions/documentation.html