The maps_to key in VDI.other_config is used during cross-pool migration to map local VDIs to their remote destinations. An attacker with root access (obtainable via BOC-1, MOKSHA-2026-0001) can modify maps_to in the XAPI database mid-migration, redirecting disk operations to an attacker-controlled VDI on the destination pool. The import code reads the modified value via Ref.of_string() with no validation. This enables cross-tenant data exfiltration and data corruption during live migration - a critical window where disk state is in transit between pools.
VDI.other_config is a Map(String, String) field writable by vm-admin. The maps_to key stores a VDI reference used during inter-pool migration to map local VDIs to their remote counterparts.
During cross-pool migration, XAPI writes the maps_to key to VDI.other_config on the source pool:
(* xapi_vm_migrate.ml:593-601 *)
Db.VDI.set_other_config
~__context ~self:vdi
~key:Constants.storage_migrate_vdi_map_key (* "maps_to" *)
~value:(Ref.string_of remote_vdi)
On the destination pool, import.ml:991-997 reads the maps_to key and uses it to look up the target VDI via Ref.of_string():
let mapto =
try Some (Ref.of_string (List.assoc "maps_to" other_config))
with _ -> None
No validation occurs on the value. Ref.of_string() accepts any string and returns it as a VDI reference. If the attacker has modified this value to point to a different VDI, the migration engine maps the source VM's disk to the wrong destination VDI.
XAPI overwrites maps_to at migration start. A vm-admin cannot pre-set the value before migration and have it survive - XAPI's write at line 593 replaces it. The attack requires modifying the value after XAPI sets it but before the destination reads it. This mid-flight modification requires root access to the XAPI database, which BOC-1 S3 provides.
Missing per-key RBAC. VDI.other_config has map_keys_roles protection only for folder and XenCenter.CustomFields.* (UI keys). The maps_to key has no per-key protection.
Migration-internal state in user-writable field. The maps_to key stores migration engine internal state in a user-writable map field. This state should be in a protected internal-only field.
No validation on import. import.ml reads maps_to via Ref.of_string() without verifying that the reference points to a VDI on the correct SR, belongs to the correct migration session, or was set by a trusted code path.
| Scenario | Impact | Pre-conditions | Status |
|---|---|---|---|
| Migration disk swap | Migrated VM boots with attacker-controlled disk data on destination | BOC-1 root access + active cross-pool migration | Write confirmed; mid-flight exploitation modeled |
| Cross-tenant data exfiltration | Source VM's disk mapped to attacker-accessible VDI on destination | Same as above + multi-tenant environment | Modeled |
| Data corruption | Source VM's disk data written to wrong VDI, corrupting destination data | Same as above | Modeled |
VDI.other_config:maps_to writes by non-XAPI sessions during active migrationsmaps_to values that change after the migration engine sets themVDI.other_config for unexpected maps_to values after migrations completeSeparate maps_to from other_config. Migration-internal state should not be stored in a user-writable map field. Move maps_to to a protected internal-only field that cannot be modified via the map API.
Add map_keys_roles. Add per-key RBAC for maps_to requiring _R_POOL_ADMIN in datamodel.ml.
Validate on import. import.ml should verify that the maps_to VDI reference points to a VDI on the expected SR and was set as part of the current migration session.
Upstream patches exist. They are held privately pending coordinated disclosure.
Disclosure:
xapi_vm_migrate.ml:593-639 (maps_to write), import.ml:991-997, 1169-1180 (maps_to read), constants.ml:286 (storage_migrate_vdi_map_key = "maps_to")disclosure/advisories/doc-security-advisory.mdresearch/investigations/vdi-other-config.md (section 13: backend verification)Discovered and reported by Jakob Wolffhechel, Moksha.