Skip to content

Commit e3cf679

Browse files
committed
xapi_vm: Implement per-key RBAC checking for VM.platform
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>
1 parent 2469636 commit e3cf679

5 files changed

Lines changed: 91 additions & 5 deletions

File tree

ocaml/idl/datamodel_vm.ml

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2387,7 +2387,8 @@ let sysprep =
23872387
module Other_config = struct
23882388
let protected_keys =
23892389
[
2390-
("pci", _R_POOL_ADMIN)
2390+
("hvm_serial", _R_POOL_ADMIN)
2391+
; ("pci", _R_POOL_ADMIN)
23912392
; ("folder", _R_VM_OP)
23922393
; ("XenCenter.CustomFields.*", _R_VM_OP)
23932394
]
@@ -2437,6 +2438,51 @@ module Other_config = struct
24372438
~flags:[`Session] ()
24382439
end
24392440

2441+
module Platform = struct
2442+
let protected_keys = [("hvm_serial", _R_POOL_ADMIN)]
2443+
2444+
let call =
2445+
call
2446+
~lifecycle:[(Published, rel_rio, "platform-specific configuration")]
2447+
~allowed_roles:_R_VM_ADMIN
2448+
2449+
let add_to_platform =
2450+
call ~name:"add_to_platform"
2451+
~doc:"Add the given key-value pair to the platform field of the given VM."
2452+
~params:
2453+
[
2454+
(Ref _vm, "self", "reference to object")
2455+
; (String, "key", "Key to add")
2456+
; (String, "value", "Value to add")
2457+
]
2458+
~map_keys_roles:protected_keys ~flags:[`Session] ()
2459+
2460+
let remove_from_platform =
2461+
call ~name:"remove_from_platform"
2462+
~doc:
2463+
"Remove the given key and its corresponding value from the platform \
2464+
field of the given VM. If the key is not in that Map, then do \
2465+
nothing."
2466+
~params:
2467+
[
2468+
(Ref _vm, "self", "reference to object")
2469+
; (String, "key", "Key of entry to remove")
2470+
]
2471+
~map_keys_roles:protected_keys ~flags:[`Session] ()
2472+
2473+
(* map_keys_roles can't be cited here, since they're only implemented for
2474+
{add_to,remove_from}_platform, RBAC handling is done in a manual
2475+
implementation. *)
2476+
let set_platform =
2477+
call ~name:"set_platform" ~doc:"Set the platform field of the given VM."
2478+
~params:
2479+
[
2480+
(Ref _vm, "self", "reference to object")
2481+
; (Map (String, String), "value", "New value to set")
2482+
]
2483+
~flags:[`Session] ()
2484+
end
2485+
24402486
let vm_uefi_mode =
24412487
Enum
24422488
( "vm_uefi_mode"
@@ -2643,6 +2689,9 @@ let t =
26432689
; Other_config.add_to_other_config
26442690
; Other_config.remove_from_other_config
26452691
; Other_config.set_other_config
2692+
; Platform.add_to_platform
2693+
; Platform.remove_from_platform
2694+
; Platform.set_platform
26462695
]
26472696
~contents:
26482697
([
@@ -2771,9 +2820,10 @@ let t =
27712820
~qualifier:DynamicRO ~ty:(Set (Ref _vtpm)) "VTPMs" "virtual TPMs"
27722821
; namespace ~name:"PV" ~contents:pv ()
27732822
; namespace ~name:"HVM" ~contents:hvm ()
2774-
; field
2823+
; field ~qualifier:StaticRO
27752824
~ty:(Map (String, String))
27762825
~lifecycle:[(Published, rel_rio, "platform-specific configuration")]
2826+
~map_keys_roles:[("hvm_serial", _R_POOL_ADMIN)]
27772827
"platform" "platform-specific configuration"
27782828
; field
27792829
~lifecycle:
@@ -2789,6 +2839,7 @@ let t =
27892839
~map_keys_roles:
27902840
[
27912841
("pci", _R_POOL_ADMIN)
2842+
; ("hvm_serial", _R_POOL_ADMIN)
27922843
; ("folder", _R_VM_OP)
27932844
; ("XenCenter.CustomFields.*", _R_VM_OP)
27942845
]

ocaml/xapi/helpers.ml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2571,9 +2571,9 @@ let match_protected_key objname fieldname =
25712571
entire field is usually higher than the role(s) required for
25722572
individually-protected keys.
25732573
2574-
Task and VM's "set_other_config" are special cases where lower-privileged
2575-
sessions must be able to manipulate a subset of entries (those not
2576-
protected by a more privileged role).
2574+
{Task,VM}.set_other_config and VM.set_platform are special cases where
2575+
lower-privileged sessions must be able to manipulate a subset of entries
2576+
(those not protected by a more privileged role).
25772577
*)
25782578
let set_map_with_rbac ~__context ~self ~value ~get_fn ~set_fn ~match_protected
25792579
~object_name ~field_name =

ocaml/xapi/message_forwarding.ml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3194,6 +3194,20 @@ functor
31943194
let set_other_config ~__context ~self ~value =
31953195
info "VM.set_other_config: self = '%s'" (vm_uuid ~__context self) ;
31963196
Local.VM.set_other_config ~__context ~self ~value
3197+
3198+
let add_to_platform ~__context ~self ~key ~value =
3199+
info "VM.add_to_platform: self = '%s', key = '%s'"
3200+
(vm_uuid ~__context self) key ;
3201+
Local.VM.add_to_platform ~__context ~self ~key ~value
3202+
3203+
let remove_from_platform ~__context ~self ~key =
3204+
info "VM.remove_from_platform: self = '%s', key = '%s'"
3205+
(vm_uuid ~__context self) key ;
3206+
Local.VM.remove_from_platform ~__context ~self ~key
3207+
3208+
let set_platform ~__context ~self ~value =
3209+
info "VM.set_platform: self = '%s'" (vm_uuid ~__context self) ;
3210+
Local.VM.set_platform ~__context ~self ~value
31973211
end
31983212

31993213
module VM_metrics = struct end

ocaml/xapi/xapi_vm.ml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1794,3 +1794,15 @@ let set_other_config ~__context ~self ~value =
17941794
Helpers.set_map_with_rbac ~__context ~self ~value
17951795
~get_fn:Db.VM.get_other_config ~set_fn:Db.VM.set_other_config
17961796
~match_protected ~object_name:"vm" ~field_name:"other_config"
1797+
1798+
let add_to_platform ~__context ~self ~key ~value =
1799+
Db.VM.add_to_platform ~__context ~self ~key ~value
1800+
1801+
let remove_from_platform ~__context ~self ~key =
1802+
Db.VM.remove_from_platform ~__context ~self ~key
1803+
1804+
let set_platform ~__context ~self ~value =
1805+
let match_protected = Helpers.match_protected_key "VM" in
1806+
Helpers.set_map_with_rbac ~__context ~self ~value ~get_fn:Db.VM.get_platform
1807+
~set_fn:Db.VM.set_platform ~match_protected ~object_name:"vm"
1808+
~field_name:"platform"

ocaml/xapi/xapi_vm.mli

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,3 +466,12 @@ val remove_from_other_config :
466466

467467
val set_other_config :
468468
__context:Context.t -> self:API.ref_VM -> value:(string * string) list -> unit
469+
470+
val add_to_platform :
471+
__context:Context.t -> self:API.ref_VM -> key:string -> value:string -> unit
472+
473+
val remove_from_platform :
474+
__context:Context.t -> self:API.ref_VM -> key:string -> unit
475+
476+
val set_platform :
477+
__context:Context.t -> self:API.ref_VM -> value:(string * string) list -> unit

0 commit comments

Comments
 (0)