From 8e7053981d380d5cdae83c0842632ee144d46d43 Mon Sep 17 00:00:00 2001 From: Stanislaw Grams Date: Tue, 27 Oct 2026 09:28:01 +0100 Subject: [PATCH] fix(migtd/cvmemu): drop two-phase rebind from AzCVMEmu tooling Commit 433dd79 removed the PREPARE/FINALIZE rebind model from the firmware per GHCI 1.5, but the AzCVMEmu emulator, CLI, runner script, and CI matrix still carried it. The emulator wrote the operation byte at payload offset 10, which the firmware now treats as reserved and rejects when non-zero, so `--operation rebind-finalize` always failed with InvalidParameter and `rebind-prepare` only worked by accident. Remove the operation field from the emulated StartRebinding request and zero bytes 10..16 as reserved. Replace the two CLI operations with a single `rebind` operation in the emulator binary and migtdemu.sh, update the help text to describe the single-phase handshake, and point the integration-emu workflow at the new operation name. Assisted-by: GitHub Copilot:Claude Opus 4.6 Signed-off-by: Stanislaw Grams --- .github/workflows/integration-emu.yml | 12 +++--- .../tdx-tdcall/src/tdx_emu.rs | 18 +++----- migtdemu.sh | 27 ++++++------ src/migtd/src/bin/migtd/cvmemu.rs | 43 ++++--------------- 4 files changed, 33 insertions(+), 67 deletions(-) diff --git a/.github/workflows/integration-emu.yml b/.github/workflows/integration-emu.yml index edfc05c4e..47762bf8d 100644 --- a/.github/workflows/integration-emu.yml +++ b/.github/workflows/integration-emu.yml @@ -50,18 +50,18 @@ jobs: test-command: "./migtdemu.sh --policy-v2 --policy-file ./config/AzCVMEmu/policy_v2_signed.json --policy-issuer-chain-file ./config/AzCVMEmu/policy_issuer_chain.pem --mock-report --features igvm-attest --both --no-sudo --log-level info" artifact-name: "policy-v2-igvm-test-logs" - - test-name: "Rebind Prepare (Skip RA)" + - test-name: "Rebind (Skip RA)" test-type: "rebind-skip-ra" install-jq: 'true' timeout-seconds: 300 - test-command: "./migtdemu.sh --operation rebind-prepare --policy-file ./config/AzCVMEmu/policy_v2_signed.json --policy-issuer-chain-file ./config/AzCVMEmu/policy_issuer_chain.pem --skip-ra --debug --both --no-sudo --log-level info" + test-command: "./migtdemu.sh --operation rebind --policy-file ./config/AzCVMEmu/policy_v2_signed.json --policy-issuer-chain-file ./config/AzCVMEmu/policy_issuer_chain.pem --skip-ra --debug --both --no-sudo --log-level info" artifact-name: "rebind-skip-ra-test-logs" - - test-name: "Rebind Prepare (Mock Report)" + - test-name: "Rebind (Mock Report)" test-type: "rebind-mock" install-jq: 'true' timeout-seconds: 900 - test-command: "./migtdemu.sh --operation rebind-prepare --policy-file ./config/AzCVMEmu/policy_v2_signed.json --policy-issuer-chain-file ./config/AzCVMEmu/policy_issuer_chain.pem --mock-report --both --no-sudo --log-level info" + test-command: "./migtdemu.sh --operation rebind --policy-file ./config/AzCVMEmu/policy_v2_signed.json --policy-issuer-chain-file ./config/AzCVMEmu/policy_issuer_chain.pem --mock-report --both --no-sudo --log-level info" artifact-name: "rebind-mock-test-logs" - test-name: "SPDM Migration (Skip RA)" @@ -92,11 +92,11 @@ jobs: test-command: "./migtdemu.sh --policy-v2 --policy-file ./target/emu-corim-policy.json --signer-anchor-file ./src/policy/test/policy_v2/corim/signer_anchor.bin --src-servtd-corim-file ./src/policy/test/policy_v2/corim/tcb_mapping.corim --dst-servtd-corim-file ./src/policy/test/policy_v2/corim/tcb_mapping_no_san.corim --mock-report --features spdm_attestation --both --no-sudo --log-level info" artifact-name: "spdm-policy-v2-corim-identity-test-logs" - - test-name: "SPDM Rebind Prepare (Skip RA)" + - test-name: "SPDM Rebind (Skip RA)" test-type: "spdm-rebind-skip-ra" install-jq: 'true' timeout-seconds: 300 - test-command: "./migtdemu.sh --operation rebind-prepare --policy-file ./config/AzCVMEmu/policy_v2_signed.json --policy-issuer-chain-file ./config/AzCVMEmu/policy_issuer_chain.pem --skip-ra --debug --features spdm_attestation --both --no-sudo --log-level info" + test-command: "./migtdemu.sh --operation rebind --policy-file ./config/AzCVMEmu/policy_v2_signed.json --policy-issuer-chain-file ./config/AzCVMEmu/policy_issuer_chain.pem --skip-ra --debug --features spdm_attestation --both --no-sudo --log-level info" artifact-name: "spdm-rebind-skip-ra-test-logs" - test-name: "Mock Quote Retry" diff --git a/deps/td-shim-AzCVMEmu/tdx-tdcall/src/tdx_emu.rs b/deps/td-shim-AzCVMEmu/tdx-tdcall/src/tdx_emu.rs index b4d9ded14..813dd1d5a 100644 --- a/deps/td-shim-AzCVMEmu/tdx-tdcall/src/tdx_emu.rs +++ b/deps/td-shim-AzCVMEmu/tdx-tdcall/src/tdx_emu.rs @@ -66,7 +66,6 @@ pub enum EmuMigRequest { StartRebinding { request_id: u64, rebinding_src: u8, - operation: u8, target_td_uuid: [u64; 4], binding_handle: u64, }, @@ -174,7 +173,6 @@ pub fn set_emulated_enable_log_area(request_id: u64, log_max_level: u8) { pub fn set_emulated_start_rebinding( request_id: u64, rebinding_src: u8, - operation: u8, target_td_uuid: [u64; 4], binding_handle: u64, ) { @@ -201,7 +199,6 @@ pub fn set_emulated_start_rebinding( set_emulated_mig_request(EmuMigRequest::StartRebinding { request_id, rebinding_src, - operation, target_td_uuid, binding_handle, }); @@ -706,7 +703,6 @@ pub fn tdvmcall_migtd_waitforrequest( EmuMigRequest::StartRebinding { request_id, rebinding_src, - operation, target_td_uuid, binding_handle, } => { @@ -715,8 +711,7 @@ pub fn tdvmcall_migtd_waitforrequest( // [0..8] mig_request_id (u64) // [8] rebinding_src (u8) // [9] has_init_data (u8) - 0 for emulation - // [10] operation (u8) - // [11..16] reserved [0; 5] + // [10..16] reserved [0; 6] // [16..48] target_td_uuid ([u64; 4]) // [48..56] binding_handle (u64) const START_REBINDING_PAYLOAD_LEN: usize = 56; @@ -744,10 +739,8 @@ pub fn tdvmcall_migtd_waitforrequest( payload[8] = rebinding_src; // has_init_data = 0 (no inline init data in emulation; fetched locally) payload[9] = 0; - // operation - payload[10] = operation; - // reserved [5 bytes] - for b in &mut payload[11..16] { + // reserved [6 bytes] + for b in &mut payload[10..16] { *b = 0; } // target_td_uuid [u64; 4] @@ -760,10 +753,9 @@ pub fn tdvmcall_migtd_waitforrequest( payload[48..56].copy_from_slice(&binding_handle.to_le_bytes()); log::info!( - "tdvmcall_migtd_waitforrequest: StartRebinding request_id={} src={} op={}", + "tdvmcall_migtd_waitforrequest: StartRebinding request_id={} src={}", request_id, - rebinding_src, - operation + rebinding_src ); } EmuMigRequest::GetMigtdData { diff --git a/migtdemu.sh b/migtdemu.sh index 3d51e4c88..4ea475041 100755 --- a/migtdemu.sh +++ b/migtdemu.sh @@ -18,7 +18,7 @@ DEFAULT_DEST_IP="127.0.0.1" DEFAULT_DEST_PORT="8001" DEFAULT_BUILD_MODE="release" DEFAULT_NUM_CPUS="1" -DEFAULT_OPERATION="migration" # migration, rebind-prepare, or rebind-finalize +DEFAULT_OPERATION="migration" # migration or rebind USE_SUDO=true RUN_BOTH=false SKIP_RA=false @@ -51,7 +51,7 @@ show_usage() { echo "Options:" echo " -r, --role ROLE Set role as 'source' or 'destination' (default: source)" echo " -i, --request-id ID Set migration request ID (default: 1)" - echo " -o, --operation OP Set operation: 'migration' (default), 'rebind-prepare', or 'rebind-finalize'" + echo " -o, --operation OP Set operation: 'migration' (default) or 'rebind'" echo " -d, --dest-ip IP Set destination IP address (default: 127.0.0.1)" echo " -p, --dest-port PORT Set destination port (default: 8001)" echo " --policy-file FILE Set policy file path (default: config/policy.json)" @@ -103,13 +103,13 @@ show_usage() { echo " the actual migration, ensuring logging is enabled and a TD report is generated." echo " - CPU affinity is controlled via taskset. Use --num-cpus to specify the number of CPUs" echo " (e.g., 2 means CPUs 0-1, 4 means CPUs 0-3). Default is 1 CPU for single-threaded behavior." - echo " - Rebinding operations (rebind-prepare, rebind-finalize) always require policy_v2, which" - echo " is enabled automatically. Specify a policy and an issuer chain or signer anchor." + echo " - The rebinding operation ('rebind') always requires policy_v2, which is enabled" + echo " automatically. Specify a policy and an issuer chain or signer anchor." echo " - Anchor-only JSON policies need an embedded servtdTcbMappingIssuerChain. CoRIM-only" echo " policies need --servtd-corim-file and a numbered servtdCrl in policyData." echo " Explicit per-side policies or endorsement files disable automatic policy generation." - echo " - The 'rebind-prepare' operation performs the actual rebinding handshake (TLS," - echo " token exchange, and approval). 'rebind-finalize' clears the session token." + echo " - The 'rebind' operation performs the complete single-phase rebinding handshake" + echo " (TLS/SPDM session, token exchange, and approval) per GHCI 1.5." echo echo "Examples:" echo " # Migration testing (includes EnableLogArea → GetTDReport → StartMigration)" @@ -133,11 +133,10 @@ show_usage() { echo " $0 --num-cpus 3 --both # Run with 3 CPUs (0-2)" echo echo " # Rebinding examples (a policy and an issuer chain or signer anchor are required):" - echo " $0 --operation rebind-prepare --policy-file ./config/AzCVMEmu/policy_v2_signed.json --policy-issuer-chain-file ./config/AzCVMEmu/policy_issuer_chain.pem --skip-ra --both" - echo " $0 --operation rebind-prepare --policy-file ./config/AzCVMEmu/policy_v2_signed.json --policy-issuer-chain-file ./config/AzCVMEmu/policy_issuer_chain.pem --mock-report --both" - echo " $0 --operation rebind-finalize --policy-file ./config/AzCVMEmu/policy_v2_signed.json --policy-issuer-chain-file ./config/AzCVMEmu/policy_issuer_chain.pem --mock-report --both" - echo " $0 --operation rebind-prepare --policy-file ./config/AzCVMEmu/policy_v2_signed.json --policy-issuer-chain-file ./config/AzCVMEmu/policy_issuer_chain.pem --role destination --mock-report" - echo " $0 --operation rebind-prepare --policy-file ./config/AzCVMEmu/policy_v2_signed.json --policy-issuer-chain-file ./config/AzCVMEmu/policy_issuer_chain.pem --debug --log-level trace --mock-report --both" + echo " $0 --operation rebind --policy-file ./config/AzCVMEmu/policy_v2_signed.json --policy-issuer-chain-file ./config/AzCVMEmu/policy_issuer_chain.pem --skip-ra --both" + echo " $0 --operation rebind --policy-file ./config/AzCVMEmu/policy_v2_signed.json --policy-issuer-chain-file ./config/AzCVMEmu/policy_issuer_chain.pem --mock-report --both" + echo " $0 --operation rebind --policy-file ./config/AzCVMEmu/policy_v2_signed.json --policy-issuer-chain-file ./config/AzCVMEmu/policy_issuer_chain.pem --role destination --mock-report" + echo " $0 --operation rebind --policy-file ./config/AzCVMEmu/policy_v2_signed.json --policy-issuer-chain-file ./config/AzCVMEmu/policy_issuer_chain.pem --debug --log-level trace --mock-report --both" } # Function to check if file exists @@ -406,14 +405,14 @@ while [[ $# -gt 0 ]]; do done # Validate operation -if [[ "$OPERATION" != "migration" && "$OPERATION" != "rebind-prepare" && "$OPERATION" != "rebind-finalize" ]]; then - echo -e "${RED}Error: Operation must be 'migration', 'rebind-prepare', or 'rebind-finalize', got: $OPERATION${NC}" >&2 +if [[ "$OPERATION" != "migration" && "$OPERATION" != "rebind" ]]; then + echo -e "${RED}Error: Operation must be 'migration' or 'rebind', got: $OPERATION${NC}" >&2 exit 1 fi # Detect rebind mode IS_REBIND=false -if [[ "$OPERATION" == "rebind-prepare" || "$OPERATION" == "rebind-finalize" ]]; then +if [[ "$OPERATION" == "rebind" ]]; then IS_REBIND=true # Rebinding always requires policy_v2 USE_POLICY_V2=true diff --git a/src/migtd/src/bin/migtd/cvmemu.rs b/src/migtd/src/bin/migtd/cvmemu.rs index f5ec3bd71..4a3b5356d 100644 --- a/src/migtd/src/bin/migtd/cvmemu.rs +++ b/src/migtd/src/bin/migtd/cvmemu.rs @@ -234,17 +234,13 @@ fn parse_commandline_args() { operation = "migration"; i += 2; } - "rebind-prepare" | "rebind_prepare" | "rp" => { - operation = "rebind-prepare"; - i += 2; - } - "rebind-finalize" | "rebind_finalize" | "rf" => { - operation = "rebind-finalize"; + "rebind" | "rb" => { + operation = "rebind"; i += 2; } _ => { println!( - "Invalid operation: {}. Use 'migration', 'rebind-prepare', or 'rebind-finalize'", + "Invalid operation: {}. Use 'migration' or 'rebind'", args[i + 1] ); print_usage(); @@ -403,29 +399,9 @@ fn parse_commandline_args() { ); set_emulated_start_migration(mig_request_id, migration_source, td_uuid, binding_handle); } - "rebind-prepare" => { - log::info!( - "Setting up rebind-prepare flow (EnableLogArea → GetMigtdData → StartRebinding)\n" - ); - set_emulated_start_rebinding( - mig_request_id, - migration_source, - 0, // MIGTD_REBIND_OP_PREPARE - td_uuid, - binding_handle, - ); - } - "rebind-finalize" => { - log::info!( - "Setting up rebind-finalize flow (EnableLogArea → GetMigtdData → StartRebinding)\n" - ); - set_emulated_start_rebinding( - mig_request_id, - migration_source, - 1, // MIGTD_REBIND_OP_FINALIZE - td_uuid, - binding_handle, - ); + "rebind" => { + log::info!("Setting up rebind flow (EnableLogArea → GetMigtdData → StartRebinding)\n"); + set_emulated_start_rebinding(mig_request_id, migration_source, td_uuid, binding_handle); } _ => unreachable!(), } @@ -450,7 +426,7 @@ fn print_usage() { println!( " --role, -m ROLE Set role as 'source' or 'destination' (default: source)" ); - println!(" --operation, -o OP Set operation: 'migration' (default), 'rebind-prepare', or 'rebind-finalize'"); + println!(" --operation, -o OP Set operation: 'migration' (default) or 'rebind'"); println!(" --uuid, -u U1 U2 U3 U4 Set target TD UUID as four integers (default: 1 2 3 4)"); println!(" --binding, -b HANDLE Set binding handle as hex or decimal (default: 0x1234)"); println!(" --dest-ip, -d IP Set destination IP address for connection (default: 127.0.0.1)"); @@ -467,9 +443,8 @@ fn print_usage() { println!(" ./migtd --role source --dest-ip 192.168.1.100 --dest-port 8001"); println!(); println!(" # Rebinding:"); - println!(" ./migtd --role source --operation rebind-prepare --request-id 42"); - println!(" ./migtd -m destination -o rebind-prepare -r 42"); - println!(" ./migtd --role source --operation rebind-finalize --request-id 42"); + println!(" ./migtd --role source --operation rebind --request-id 42"); + println!(" ./migtd -m destination -o rebind -r 42"); } fn handle_pre_mig_emu() -> i32 {