A pool-operator in XAPI-based hypervisors (XenServer, XCP-ng) can manipulate the indestructible key in SR.other_config to either prevent authorized SR destruction (denial-of-service) or remove destruction protection from a protected SR (security bypass). The assert_sr_not_indestructible function at xapi_sr.ml:433-442 checks for this key before allowing SR.destroy and SR.forget operations. Setting indestructible=true on any SR blocks both operations, requiring direct database manipulation to remove the key. Conversely, removing the key from a legitimately protected SR enables unauthorized destruction. The SR.other_config field has no map_keys_roles entries for infrastructure keys.
SR.other_config is a Map(String, String) field defined at datamodel.ml:4930-4935 with _R_POOL_OP as the minimum write role inherited from the SR class default.
The protection check:
xapi_sr.ml:433-442:
let assert_sr_not_indestructible ~__context ~sr =
let oc = Db.SR.get_other_config ~__context ~self:sr in
if List.mem_assoc "indestructible" oc
&& List.assoc "indestructible" oc = "true" then
raise (Api_errors.Server_error (Api_errors.sr_indestructible, [Ref.string_of sr]))
This check is enforced before SR.destroy at message_forwarding.ml:5024. The check is a simple string comparison with no RBAC differentiation - the same pool-operator who can set the key can also remove it. This creates two attack vectors:
DoS: Set indestructible=true on any SR. The SR cannot be destroyed or forgotten through normal API operations. Removing the key requires direct database access.
Protection bypass: Remove indestructible=true from a legitimately protected SR (set by a pool-admin for policy reasons). The pool-operator can then proceed to destroy the SR.
Missing RBAC protection. SR.other_config has map_keys_roles entries only for UI keys (folder, XenCenter.CustomFields.*). The indestructible key is writable by any pool-operator.
No RBAC differentiation for destruction protection. The same role that can set indestructible can also remove it, making the protection ineffective against lateral attackers at the same privilege level.
No write-time validation. XAPI accepts any value for the key without checking whether the caller should be allowed to modify SR lifecycle policy.
set_other_config RBAC bypass. The set_other_config method replaces the entire map atomically and bypasses map_keys_roles per-key checks.
indestructible can be bypassed| Scenario | Impact | Pre-conditions | Status |
|---|---|---|---|
| SR locking DoS | SR cannot be destroyed or forgotten; requires DB-level intervention | pool-operator | Source-traced |
| Destruction protection bypass | Attacker removes protection from critical SR, enables unauthorized destruction | pool-operator | Source-traced |
| Pool cleanup sabotage | Set all SRs to indestructible, blocking decommissioning | pool-operator | Modeled |
| BOC-1 chain | vm-admin locks/unlocks SRs via RBAC collapse | vm-admin, BOC-1 | Source-traced |
SR.other_config for additions or removals of the indestructible keySR.destroy and SR.forget failures for SR_INDESTRUCTIBLE errorsdisclosure/vendor-detection-guidance.mdSR.other_config entries for unexpected indestructible valuesAdd map_keys_roles protection. Restrict the indestructible key to _R_POOL_ADMIN in datamodel.ml. This ensures pool-operators cannot modify SR lifecycle policy.
Separate destruction protection. Move the indestructible flag to a dedicated first-class field with its own RBAC control, rather than relying on an unprotected other_config key.
Upstream patches exist. They are held privately pending coordinated disclosure.
Disclosure:
datamodel.ml:4930-4935 (SR.other_config field definition), xapi_sr.ml:433-442 (assert_sr_not_indestructible), message_forwarding.ml:5024 (check before SR.destroy)disclosure/advisories/soc-security-advisory.md (SOC-4)research/investigations/sr-other-config.mdDiscovered and reported by Jakob Wolffhechel, Moksha.