A pool-operator in XAPI-based hypervisors (XenServer, XCP-ng) can inject the LUNperVDI key into SR.sm_config. The key is defined at SR.py:37 and SR._addLUNperVDIkey() exists at SR.py:226, but source analysis confirms _addLUNperVDIkey() is never called by any SM driver and no driver reads sm_config["LUNperVDI"] to decide behavior. The key is an SR-type marker, not a behavioral toggle. Impact is limited to key persistence in the XAPI database without backend consumption. The SR.sm_config field has zero map_keys_roles entries and remains writable after SR creation.
SR.sm_config is a Map(String, String) field writable by pool-operator. The LUNperVDI key was intended to mark whether an SR uses one-LUN-per-VDI mode.
The code path:
SR._addLUNperVDIkey() is defined at SR.py:226 to set sm_config["LUNperVDI"] = "true"_addLUNperVDIkey() is never called by any SM driver in the codebasesm_config["LUNperVDI"] to decide behaviorLUNperVDI.py is a separate driver module (used by RawISCSISR and HBASR) - it is the raw-LUN driver itself, not something controlled by the sm_config keypool-operator can inject the key: SR.add_to_sm_config(sr, "LUNperVDI", "true")The xe CLI rejects sm_config writes with "Map field 'sm-config' is read-only", but direct XenAPI calls (SR.add_to_sm_config, SR.remove_from_sm_config) succeed. The CLI provides a false sense of immutability.
Missing field immutability. SR.sm_config is qualifier:RW despite containing keys that define the SR's storage architecture. The LUNperVDI key is set during SR.create and should be immutable afterward.
Missing RBAC protection. SR.sm_config has zero map_keys_roles entries. The LUNperVDI key inherits the class default _R_POOL_OP.
CLI/API inconsistency. The xe CLI rejects sm_config writes, but the XenAPI accepts them. This creates a false sense of immutability for operators who only use the CLI.
Dead code marker. _addLUNperVDIkey() is defined but never called. The key exists as a vestigial marker with no runtime consumer.
LUNperVDI key is dead code (never read by any SM driver)| Scenario | Impact | Pre-conditions | Status |
|---|---|---|---|
| Key injection | LUNperVDI=true persists in sm_config | pool-operator | Source-traced (W) |
| No backend effect | _addLUNperVDIkey() is dead code; no driver reads the key |
n/a | Confirmed via source trace |
LUNperVDI key. The key persists but has no backend effect (dead code).map_keys_roles) remains valid regardless of backend impact.SR.sm_config for modifications to the LUNperVDI key after SR creationLUNperVDI key changes on any active SRSR.sm_config snapshots between monitoring intervals for driftdisclosure/vendor-detection-guidance.mdSR.sm_config records for unexpected LUNperVDI values (indicator of unauthorized metadata writes)SR.add_to_sm_config calls from non-SM sessionsAdd map_keys_roles. Protect LUNperVDI at _R_LOCAL_ROOT_ONLY in datamodel.ml. While the key has no backend consumer, the RBAC violation (pool-operator writing driver metadata) remains valid.
Remove dead code. _addLUNperVDIkey() at SR.py:226 is never called and can be safely removed.
Disclosure:
datamodel.ml:4949-4953 (SR.sm_config field definition), SR.py:37 (LUNPERVDI constant), SR.py:228 (_addLUNperVDIkey writes the key)disclosure/advisories/ssmc-security-advisory.md (SSMC-5)research/investigations/sr-sm-config.mdDiscovered and reported by Jakob Wolffhechel, Moksha.