MOKSHA-2026-0060: Arbitrary Integer Passthrough to ionice via VBD.qos_algorithm_params

Advisory IDMOKSHA-2026-0060
Semantic IDBQP-2
Published2026-04-24
CVSS 3.15.3 Medium
CVSS 3.1 VectorAV:N/AC:H/PR:L/UI:N/S:U/C:N/I:H/A:N
CVSS 4.05.3 Medium
CVSS 4.0 VectorAV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N
XAPI ObjectVBD
XAPI Fieldqos_algorithm_params:class
Entry Rolevm-admin
ResearcherJakob Wolffhechel, Moksha

Affected Products

VendorProductVersions
Citrix / Cloud Software GroupXenServer / Citrix Hypervisorall versions (shared XAPI codebase)
VatesXCP-ng8.3.0

Summary

A vm-admin in XAPI-based hypervisors (XenServer, XCP-ng) can pass arbitrary integer values to the Linux ionice binary via the class key in VBD.qos_algorithm_params. The qos_class parser at xapi_xenops.ml:595-600 accepts any integer string via Other (int_of_string s), and Ionice.to_class_param at ionice.ml:30-31 passes Other x directly as the -n argument to ionice. No range validation is performed - the valid range is 0-7, but negative integers and values far outside this range are accepted and forwarded to the kernel. Kernel behavior with out-of-range ionice priority values is undefined. The VBD.qos_algorithm_params field has zero map_keys_roles entries, and changes take effect immediately without VBD replug.

Vulnerability Description

VBD.qos_algorithm_params is a Map(String, String) field writable by vm-admin with zero per-key RBAC. When VBD.qos_algorithm_type is set to ionice, the class key is parsed to determine the I/O scheduling priority for VBD kernel threads.

The code path:

  1. vm-admin sets an out-of-range value: VBD.add_to_qos_algorithm_params(vbd, "class", "-999")
  2. XAPI parses the class key at xapi_xenops.ml:595-600:
    | Some s -> (
      try Other (int_of_string s)    (* accepts ANY integer *)
      with _ -> ... Normal
    )
    
  3. Other -999 is passed to xenopsd as part of the Ionice(qos_scheduler) struct
  4. Ionice.to_class_param at ionice.ml:30-31 converts Other x to the -n argument:
    | Other x -> x    (* DIRECT PASSTHROUGH *)
    
  5. xenopsd invokes ionice -c<class> -n-999 -p<kthread_pid> via execve
  6. The kernel receives an out-of-range priority value

No shell injection is possible - xenopsd uses Forkhelpers.execute_command_get_output which calls execve() directly without a shell. The risk is kernel-level undefined behavior with out-of-range scheduling parameters.

Additionally, QoS changes are applied hot via the Needs_set_qos action request mechanism (xenops_server_xen.ml:4003-4017). When the current ionice settings differ from the target QoS, xenopsd re-invokes ionice on running kernel threads without requiring a VBD replug or VM reboot.

Root Causes

  1. Missing range validation. The qos_class parser accepts any integer via Other (int_of_string s). No bounds check enforces the valid range of 0-7.

  2. Direct passthrough in ionice wrapper. Ionice.to_class_param passes Other x directly as the -n argument without any sanitization or clamping.

  3. Missing RBAC protection. VBD.qos_algorithm_params has zero map_keys_roles entries. The class and sched keys inherit the class default _R_VM_ADMIN.

  4. Hot apply without validation. QoS changes take effect immediately on running VBDs. There is no confirmation step or secondary validation before invoking ionice with attacker-controlled values.

Affected Systems

Directly Affected

Indirectly Affected

Exploitation Scenarios

Scenario Impact Pre-conditions Status
Negative priority injection Pass negative integer to ionice -n, causing undefined kernel behavior vm-admin, ionice QoS enabled Source-traced
Extreme priority injection Pass very large integer (e.g., 999999) to ionice -n vm-admin, ionice QoS enabled Source-traced
Hot apply on running VBDs Inject arbitrary priority on running kernel threads without reboot vm-admin, running VM with ionice QoS Source-traced
BOC-1 chain vm-admin uses BOC-1 S3 to bulk-inject out-of-range priorities across all VBDs vm-admin, BOC-1 Source-traced

Chaining Analysis

Detection

Remediation

Short-Term Mitigations

Long-Term Fix

Add range validation. Validate the class value to 0-7 (the valid ionice priority range) at parse time in xapi_xenops.ml. Reject or clamp out-of-range values.

Remove Other passthrough. Replace the Other x variant in the qos_class type with a bounded integer type that enforces 0-7.

Add map_keys_roles protection. Restrict sched and class keys to _R_POOL_OP or _R_POOL_ADMIN to prevent vm-admin from modifying I/O scheduling.

Upstream patches exist. They are held privately pending coordinated disclosure.

Disclosure

Disclosure:

References

Credits

Discovered and reported by Jakob Wolffhechel, Moksha.

Jakob Wolffhechel · Moksha · Copenhagen
jakob@wolffhechel.dk · +45 3170 7337
Published 2026-04-24 08:00 CEST · cna.moksha.dk · shittrix.moksha.dk