Skip to content

xapi_vm: Implement RBAC checking for keys in VM.other_config and VM.platform#7039

Merged
robhoes merged 3 commits intoxapi-project:masterfrom
last-genius:asv/sec
Apr 28, 2026
Merged

xapi_vm: Implement RBAC checking for keys in VM.other_config and VM.platform#7039
robhoes merged 3 commits intoxapi-project:masterfrom
last-genius:asv/sec

Conversation

@last-genius
Copy link
Copy Markdown
Contributor

@last-genius last-genius commented Apr 27, 2026

Add per-key RBAC checking for VM.platform and VM.other_config, to cover a case where a lower-prileged user could circumvent permission checks on other_config:{pci,hvm_serial} and platform:hvm_serial.

Introduces a generic per-key RBAC checker for map setters based on Task's manual RBAC checker (introduced in a3f2c6e). Uses it for the fields above.

This is part of XSA-489 / CVE-2026-23562 and CVE-2026-42486

@last-genius
Copy link
Copy Markdown
Contributor Author

Best reviewed outside of Github, with colorMoved set to distinguish new lines from moved lines.

@contificate
Copy link
Copy Markdown
Contributor

Looks good to me. It'd be nice to get an "all clear" on the XenRT suites from Citrix.

@last-genius
Copy link
Copy Markdown
Contributor Author

last-genius commented Apr 27, 2026

my unit test isn't testing exactly what it claims to (it created a role without any permissions at all, not vm-admin). it seems much more complicated to test something related to external auth in unit tests than I'd imagined, plugins are required in particular:

XENAPI_MISSING_PLUGIN: [ extauth-hook ]`

So I've dropped the unit test

@lindig
Copy link
Copy Markdown
Contributor

lindig commented Apr 27, 2026

This introduces a mechanism to match keys against permissions. Would it make sense to subject all keys to a role and some keys to more specific roles? For example, we could have a permission for * (all keys) and additionally more specific keys. This way we would have one mechanism to declare permissions.

@last-genius
Copy link
Copy Markdown
Contributor Author

This introduces a mechanism to match keys against permissions. Would it make sense to subject all keys to a role and some keys to more specific roles? For example, we could have a permission for * (all keys) and additionally more specific keys. This way we would have one mechanism to declare permissions.

This is already the case, though in a less obvious way.

field gets default permissions from its object, thus for vm, * (all keys) are vm-admin-writeable by default:

    ~messages_default_allowed_roles:_R_VM_ADMIN

and then special keys have particular permissions:

            ~map_keys_roles:
              [
                ("pci", _R_POOL_ADMIN)
              ; ("folder", _R_VM_OP)
              ; ("XenCenter.CustomFields.*", _R_VM_OP)
              ]

These definitions are quite far away from each other in source code and are not obvious...

@last-genius
Copy link
Copy Markdown
Contributor Author

I've verified this fixes the issue manually

> import xmlrpc.client
> x = xmlrpc.client.ServerProxy(ip)
> s = x.session.login_with_password(user, pw)['Value']
> ref=x.VM.get_by_uuid(s, uuid)['Value']

> print(x.VM.add_to_other_config(s, ref, 'pci', 'aaa'))
{'Status': 'Failure', 'ErrorDescription': ['RBAC_PERMISSION_DENIED', 'vm.add_to_other_config/key:pci', 'No permission in user session. (Roles with this permission: pool-admin)']}
> print(x.VM.set_other_config(s, ref, {}))
{'Status': 'Failure', 'ErrorDescription': ['RBAC_PERMISSION_DENIED', 'vm.remove_from_other_config/key:pci', 'No permission in user session. (Roles with this permission: pool-admin)']}
> print(x.VM.set_other_config(s, ref, {"pci":"ddd"}))
{'Status': 'Failure', 'ErrorDescription': ['RBAC_PERMISSION_DENIED', 'vm.add_to_other_config/key:pci', 'No permission in user session. (Roles with this permission: pool-admin)']}

@lindig
Copy link
Copy Markdown
Contributor

lindig commented Apr 27, 2026

Could/should we include the wildcard * key in the list?

@last-genius
Copy link
Copy Markdown
Contributor Author

Could/should we include the wildcard * key in the list?

We could, code already supports it, not sure if we should

@lindig
Copy link
Copy Markdown
Contributor

lindig commented Apr 27, 2026

I think such an entry would add clarity; or have a comment that tells where the default role is coming from if the key does not match.

map_keys_roles parameter was RBAC checked for
{add_to,remove_from}_other_config, but set_other_config allowed
circumventing this check.

Since VM is the only object that has a key ("pci") in other_config
with the privilege level required for modification higher than that of the
other_config field generally, this meant that vm-admin could not modify the
"pci" key in other_config through add_to_other_config, but could circumvent the
check with set_other_config.

Implement a checker for VM.other_config setters based on Task's manual RBAC
checker (introduced in a3f2c6e)

This is part of XSA-489 / CVE-2026-23562

Signed-off-by: Andrii Sultanov <andriy.sultanov@vates.tech>
@last-genius
Copy link
Copy Markdown
Contributor Author

Added another commit that a fixes a similar issue for {other_config,platform}:hvm_serial

@last-genius last-genius changed the title xapi_vm: Implement RBAC checking for keys in set_other_config xapi_vm: Implement RBAC checking for keys in VM.other_config and VM.platform Apr 27, 2026
platform:hvm_serial and other_config:hvm_serial are both keys that allow host
filesystem write. Limit these to be modifiable only by pool-admin.

Implement set_platform with Helpers.set_map_with_rbac, like for
set_other_config.

This is part of XSA-489 / CVE-2026-42486

Signed-off-by: Andrii Sultanov <andriy.sultanov@vates.tech>
The only difference in the schematest comes from changing the type of the
other_config and platform fields from RW to StaticRO, which is necessary to
provide custom implementations of setters.

With a modified schematest, the diff is:

    <     "qualifier": "RW",
    ---
    >     "qualifier": "StaticRO",

Signed-off-by: Andrii Sultanov <andriy.sultanov@vates.tech>
@last-genius last-genius marked this pull request as ready for review April 28, 2026 07:30
Copy link
Copy Markdown
Contributor

@contificate contificate left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, I'm glad the old matching logic for when this was done for task was helpful.

@lindig
Copy link
Copy Markdown
Contributor

lindig commented Apr 28, 2026

Is there room to factor out the trie implementation because ocaml/xapi/xapi_task.ml contains a very similar implementation? On the other hand, it's not a lot of code.

@last-genius
Copy link
Copy Markdown
Contributor Author

Is there room to factor out the trie implementation because ocaml/xapi/xapi_task.ml contains a very similar implementation? On the other hand, it's not a lot of code.

I've moved the trie implementation from xapi_task.ml to helpers.ml entirely in the first commit

@robhoes robhoes added this pull request to the merge queue Apr 28, 2026
Merged via the queue into xapi-project:master with commit 27590e8 Apr 28, 2026
16 checks passed
@Zhengchai
Copy link
Copy Markdown
Contributor

There are 21 usage and mentioned in the XenServer customer docs about 'other_config, are there any change here will need to update the XenServer customer document also for the usage ofother_config`? Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants