Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce VTPM for guests #4780

Merged
merged 75 commits into from
Sep 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
1b1fd45
CP-38617: Add module with stubs for xenforeignmemory
psafont Dec 20, 2021
3d1a2e7
Add a test executable that works against the bindings
psafont Jan 24, 2022
afa0daf
Merge pull request #4633 from psafont/private/paus/xen-foreign
psafont Feb 24, 2022
4a77bef
CP-38626: move vtpm module to its own file
psafont Mar 7, 2022
c350afc
CP-38626: Allow manipulation of VTPM contents
psafont Mar 8, 2022
525259f
CP-38626: expose vtpm objects through xe cli
psafont Mar 9, 2022
22b8dda
Merge pull request #4644 from psafont/private/paus/vtpm-datamodel
psafont Mar 11, 2022
8986868
Merge branch 'master' into private/paus/vtpm-update
psafont Mar 11, 2022
6d675e4
Merge pull request #4649 from psafont/private/paus/vtpm-update
psafont Mar 11, 2022
ca755ae
Merge remote-tracking branch 'origin/master' into feature/vtpm
edwintorok Apr 5, 2022
9e279f6
Merge remote-tracking branch 'origin/master' into feature/vtpm
edwintorok Apr 8, 2022
6f448be
Maintenance: update quality gate after merge
edwintorok Apr 8, 2022
1a5be17
Merge pull request #4671 from edwintorok/feature/vtpm
edwintorok Apr 8, 2022
79576d5
CP-38554: functorize varstored sandbox code
psafont Mar 17, 2022
2783369
CP-39441: Enable xenopsd to directly wait on pid creation
psafont Apr 4, 2022
9b52389
CP-38554: Start up and stop SWTPM and guard for every domain
psafont Apr 4, 2022
27f2799
xenops_sandbox: use create instead of prepare
psafont Apr 6, 2022
66e2aa1
Merge pull request #4667 from psafont/private/paus/swtpm-managed
edwintorok Apr 13, 2022
1ed27f8
CP-39414: start swtpm depending on the VM's platform metadata
psafont Apr 22, 2022
d083048
CP-39414: log actual daemon name when deleting sandbox
psafont Apr 25, 2022
8dbc71e
CP-39574: Create and destroy VTPM objects attached to VMs
psafont Apr 26, 2022
1dd5bbd
Merge branch 'master' into feature/vtpm
psafont May 25, 2022
ef96b22
Merge pull request #4723 from psafont/private/paus/vtpm-merged
psafont Jun 8, 2022
b2ce504
Merge branch 'feature/vtpm' into private/paus/vtpm-param
edwintorok Jun 8, 2022
c249fa5
Merge pull request #4693 from psafont/private/paus/vtpm-param
edwintorok Jun 8, 2022
7ee7e33
maintenance: post-merge fixes
psafont Jun 8, 2022
4ff283a
xapi-idl: move Uuidm type to separate module
edwintorok Jun 9, 2022
3833d10
xapi-idl: add sexp converter to Uuidm type
edwintorok Jun 9, 2022
a8dec3a
vTPM: plumb through Uuid
edwintorok Jun 9, 2022
4e5597e
varstore-guard: add filtering for vTPM.{set,get}_contents API
edwintorok Jun 9, 2022
875da36
vTPM: add minimal support for saving/restoring state through the XAPI DB
edwintorok Jun 9, 2022
43baa4a
vTPM: add minimal migration support
edwintorok Jun 9, 2022
cca5ac7
vTPM: do not hardcode swtpm-wrapper path
edwintorok Jun 9, 2022
cb6161f
Merge pull request #4730 from edwintorok/private/edvint/vtpm-state-me…
psafont Jun 17, 2022
d72b680
CP-40032: Block VTPM creation and destruction on certain cases
psafont Jun 21, 2022
b9c99ef
CP-40032: add vtpm-create and destroy to cli
psafont Jun 21, 2022
66dc6a0
CA-368102: Send the VTPM uuid to xenops whenever its available
psafont Jun 23, 2022
bfcde2a
Merge pull request #4740 from psafont/private/paus/vtpm-create
psafont Jun 24, 2022
5ff4c2f
xenops_sandbox: only get references by creating the sandbox
psafont Jun 20, 2022
9c2dc9a
CP-39894: move xenopsd's daemon modules from device to service
psafont May 19, 2022
c516727
xenopsd/xc/service: add licensing header
psafont May 19, 2022
500bbab
CP-39894: Move all swtpm starting code to service module
psafont May 19, 2022
816d4ab
CP-39894: move all varstored starting code to service module
psafont May 19, 2022
baccccd
CP-39894: move vgpu starting code to service module
psafont May 19, 2022
5caee44
CP-39894: Replace is_pidfile and pid_path with pid_location
psafont May 23, 2022
5a6d61a
CP-39894: tweak Service.Qemu interface
psafont May 23, 2022
6173e09
CP-39894: Use pid_location for file and xenstore cleanups
psafont May 23, 2022
584bf46
CP-39894: Add Pid.File and use it in Swtpm
psafont May 23, 2022
6e4a3ca
CA-366479: Remove Qemu's pidfile on domain shutdown
psafont May 26, 2022
d0c9a18
Merge pull request #4720 from psafont/private/paus/pid-wait
psafont Jun 30, 2022
1fc0f1a
Merge branch 'master' into vtpm-merge
psafont Jul 6, 2022
053d602
Merge pull request #4747 from psafont/vtpm-merge
psafont Jul 7, 2022
684b76c
CA-368106: Do not encode vtpm contents twice
psafont Jun 27, 2022
6965944
CA-368231: Require only a VM reference for vtpm-create
psafont Jun 28, 2022
b2c86cb
CA-368231: change role for creating and destroying VTPMs
psafont Jul 4, 2022
e6ae94b
CP-39136: Reintroduce backends for VTPMs
psafont May 16, 2022
48817f6
idl: enable events for vtpm objects
psafont Jul 7, 2022
d79a445
CP-40087: replace vtpm profile with individual fields
psafont Jul 7, 2022
ffd9ca8
vtpm: allow the lifecycle of the vtpm contents to be autogenerated
psafont Jul 7, 2022
8792bca
db_upgrade: use module name for debug messages
psafont Jul 29, 2022
c2cdf85
database: use accurate message when a field lacks a default on update
psafont Aug 1, 2022
dc556b6
Merge pull request #4752 from psafont/private/paus/b128
psafont Aug 3, 2022
b2ae0c4
maintenance: comment whitespace
psafont Aug 2, 2022
19ce597
CP-39850: Copy VTPM on clone
psafont Aug 9, 2022
191ae1f
CP-39850: Block live snapshots for VMs with vTPM
psafont Aug 11, 2022
56cd793
Merge pull request #4771 from psafont/private/paus/tpm-clone
psafont Aug 15, 2022
b059fd3
CP-40284: Gate VTPM creation behind an experimental feature
psafont Aug 15, 2022
ea90f23
CP-39874: Prevent VTPMs and HA from coexisting
psafont Aug 16, 2022
97b958c
CP-40087: Display the correct names of VTPM profiles in the CLI
psafont Aug 18, 2022
cdef724
Merge pull request #4774 from psafont/private/paus/tpm_flag
psafont Aug 23, 2022
4a9614c
Merge branch 'master' into private/paus/merge-master-vtpm
psafont Aug 24, 2022
ed51796
Merge pull request #4778 from psafont/private/paus/merge-master-vtpm
psafont Aug 25, 2022
3ecb5bd
CP-40444: Add swtpm-wrapper to the repository
psafont Aug 26, 2022
9acd4dd
CP-40444: Mark VTPM class as prototype
psafont Aug 30, 2022
7b8e0f2
CP-40672: set platform/tpm_version xenstore key on vm construction
psafont Sep 7, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ install: build doc sdk doc-json
install -D ./ocaml/xenopsd/scripts/common.py $(DESTDIR)/$(XENOPSD_LIBEXECDIR)/common.py
install -D ./ocaml/xenopsd/scripts/igmp_query_injector.py $(DESTDIR)/$(XENOPSD_LIBEXECDIR)/igmp_query_injector.py
install -D ./ocaml/xenopsd/scripts/qemu-wrapper $(DESTDIR)/$(QEMU_WRAPPER_DIR)/qemu-wrapper
install -D ./ocaml/xenopsd/scripts/swtpm-wrapper $(DESTDIR)/$(QEMU_WRAPPER_DIR)/swtpm-wrapper
DESTDIR=$(DESTDIR) SBINDIR=$(SBINDIR) QEMU_WRAPPER_DIR=$(QEMU_WRAPPER_DIR) XENOPSD_LIBEXECDIR=$(XENOPSD_LIBEXECDIR) ETCDIR=$(ETCDIR) ./ocaml/xenopsd/scripts/make-custom-xenopsd.conf
# squeezed
install -D _build/install/default/bin/squeezed $(DESTDIR)/$(SBINDIR)/squeezed
Expand Down
11 changes: 10 additions & 1 deletion ocaml/database/database_test.ml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@ functor
->
()

let expect_missing_default name f =
try f ()
with
| Db_exn.DBCache_NotFound
("missing default value in datamodel for new field", name', _)
when name' = name
->
()

let expect_missing_field name f =
try f ()
with
Expand Down Expand Up @@ -515,7 +524,7 @@ functor
) ;
Printf.printf
"create_row <unique ref> <unique uuid> <missing required field>\n" ;
expect_missing_field name_label (fun () ->
expect_missing_default name_label (fun () ->
let broken_vm =
List.filter
(fun (k, _) -> k <> name_label)
Expand Down
7 changes: 6 additions & 1 deletion ocaml/database/db_cache_types.ml
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,12 @@ module Row = struct
add g c.Schema.Column.name default t
| None ->
raise
(DBCache_NotFound ("missing field", c.Schema.Column.name, ""))
(DBCache_NotFound
( "missing default value in datamodel for new field"
, c.Schema.Column.name
, ""
)
)
else
t
)
Expand Down
4 changes: 1 addition & 3 deletions ocaml/database/db_upgrade.ml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
* GNU Lesser General Public License for more details.
*)

module D = Debug.Make (struct
let name = "xapi" (* this is set to 'xapi' deliberately! :) *)
Copy link
Member

Choose a reason for hiding this comment

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

And now it has been changed away from 'xapi' deliberately? :)

Copy link
Member Author

Choose a reason for hiding this comment

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

I spelunked and found no justification for it in the commit that introduced the module. It's more helpful to have the actual module that prints the loglines, same reasoning I used to change all the unjustified ones 3 years back, it just helps whith triaging

end)
module D = Debug.Make (struct let name = __MODULE__ end)

open D
open Db_cache_types
Expand Down
20 changes: 2 additions & 18 deletions ocaml/idl/datamodel.ml
Original file line number Diff line number Diff line change
Expand Up @@ -5012,23 +5012,6 @@ module Role = struct
()
end

module VTPM = struct
let t =
create_obj ~in_db:true ~in_product_since:rel_rio ~in_oss_since:oss_since_303
~internal_deprecated_since:None ~persist:PersistEverything
~gen_constructor_destructor:true ~name:_vtpm ~descr:"A virtual TPM device"
~gen_events:false ~doccomments:[]
~messages_default_allowed_roles:_R_VM_ADMIN ~messages:[]
~contents:
[
uid _vtpm
; field ~qualifier:StaticRO ~ty:(Ref _vm) "VM" "the virtual machine"
; field ~qualifier:StaticRO ~ty:(Ref _vm) "backend"
"the domain where the backend is located"
]
()
end

module Console = struct
(** Console protocols *)
let protocol =
Expand Down Expand Up @@ -7789,7 +7772,7 @@ let all_system =
; PBD.t
; Crashdump.t
; (* misc *)
VTPM.t
Datamodel_vtpm.t
; Console.t
; (* filesystem; *)
User.t
Expand Down Expand Up @@ -8048,6 +8031,7 @@ let expose_get_all_messages_for =
; _cluster_host
; _certificate
; _repository
; _vtpm
]

let no_task_id_for = [_task; (* _alert; *) _event]
Expand Down
2 changes: 1 addition & 1 deletion ocaml/idl/datamodel_common.ml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ open Datamodel_roles
to leave a gap for potential hotfixes needing to increment the schema version.*)
let schema_major_vsn = 5

let schema_minor_vsn = 752
let schema_minor_vsn = 755

(* Historical schema versions just in case this is useful later *)
let rio_schema_major_vsn = 5
Expand Down
6 changes: 4 additions & 2 deletions ocaml/idl/datamodel_errors.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1944,9 +1944,11 @@ let _ =
error Api_errors.apply_livepatch_failed ["livepatch"]
~doc:"Failed to apply a livepatch." () ;
error Api_errors.update_guidance_changed ["guidance"]
~doc:"Guidance for the update has changed" ()
~doc:"Guidance for the update has changed" () ;

error Api_errors.vtpm_max_amount_reached ["amount"]
~doc:"The VM cannot be associated with more VTPMs." () ;

let _ =
message
(fst Api_messages.ha_pool_overcommitted)
~doc:
Expand Down
83 changes: 83 additions & 0 deletions ocaml/idl/datamodel_vtpm.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
(*
Copyright (C) Citrix Systems Inc.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; version 2.1 only. with the special
exception on linking described in file LICENSE.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
*)

open Datamodel_types
open Datamodel_common
open Datamodel_roles

let persistence_backend =
Enum ("persistence_backend", [("xapi", "This VTPM is persisted in XAPI's DB")])

let create =
call ~name:"create" ~lifecycle:[]
~doc:"Create a new VTPM instance, and return its handle."
~params:
[
(Ref _vm, "vM", "The VM reference the VTPM will be attached to")
; (Bool, "is_unique", "Whether the VTPM must be unique")
]
~result:(Ref _vtpm, "The reference of the newly created VTPM")
~allowed_roles:_R_VM_ADMIN ()

let destroy =
call ~name:"destroy" ~lifecycle:[]
~doc:"Destroy the specified VTPM instance, along with its state."
~params:[(Ref _vtpm, "self", "The reference to the VTPM object")]
~allowed_roles:_R_VM_ADMIN ()

let get_contents =
call ~name:"get_contents" ~lifecycle:[] ~doc:"Obtain the contents of the TPM"
~secret:true
~params:[(Ref _vtpm, "self", "The VTPM reference")]
~result:(String, "The contents") ~hide_from_docs:true
~allowed_roles:_R_LOCAL_ROOT_ONLY ()

let set_contents =
call ~name:"set_contents" ~lifecycle:[]
~doc:"Introduce new contents for the TPM" ~secret:true
~params:
[
(Ref _vtpm, "self", "The VTPM reference")
; (String, "contents", "The new contents")
]
~hide_from_docs:true ~allowed_roles:_R_LOCAL_ROOT_ONLY ()

let t =
create_obj ~in_db:true ~in_oss_since:oss_since_303 ~persist:PersistEverything
~lifecycle:[] ~gen_constructor_destructor:false ~name:_vtpm
~descr:"A virtual TPM device" ~gen_events:true ~doccomments:[]
~messages_default_allowed_roles:_R_POOL_ADMIN
~contents:
[
uid _vtpm
; field ~qualifier:StaticRO ~ty:(Ref _vm) "VM"
"The virtual machine the TPM is attached to"
; field ~qualifier:DynamicRO ~ty:(Ref _vm) "backend"
~default_value:(Some (VRef null_ref))
"The domain where the backend is located (unused)"
; field ~qualifier:DynamicRO ~ty:persistence_backend
~default_value:(Some (VEnum "xapi")) ~lifecycle:[]
"persistence_backend" "The backend where the vTPM is persisted"
; field ~qualifier:StaticRO ~ty:Bool ~default_value:(Some (VBool false))
~lifecycle:[] "is_unique"
"Whether the contents are never copied, satisfying the TPM spec"
; field ~qualifier:DynamicRO ~ty:Bool ~default_value:(Some (VBool false))
~lifecycle:[] "is_protected"
"Whether the contents of the VTPM are secured according to the TPM \
spec"
; field ~qualifier:DynamicRO ~ty:(Ref _secret) ~internal_only:true
~lifecycle:[] "contents" "The contents of the TPM"
]
~messages:[create; destroy; get_contents; set_contents]
()
3 changes: 2 additions & 1 deletion ocaml/idl/dune
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
datamodel_errors datamodel_roles datamodel_vm datamodel_host
datamodel_pool datamodel_cluster datamodel_cluster_host dm_api escaping
datamodel_values datamodel_schema datamodel_certificate
datamodel_diagnostics datamodel_repository datamodel_lifecycle)
datamodel_diagnostics datamodel_repository datamodel_lifecycle
datamodel_vtpm)
(libraries
ppx_sexp_conv.runtime-lib
rpclib.core
Expand Down
2 changes: 1 addition & 1 deletion ocaml/idl/schematest.ml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
let hash x = Digest.string x |> Digest.to_hex

(* BEWARE: if this changes, check that schema has been bumped accordingly *)
let last_known_schema_hash = "cc62c6cd69cb75cb16abc39922d24cf9"
let last_known_schema_hash = "7959564ea47f1bad8ab6935ccbaa1f6c"

let current_schema_hash : string =
let open Datamodel_types in
Expand Down
18 changes: 18 additions & 0 deletions ocaml/xapi-cli-server/cli_frontend.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3570,6 +3570,24 @@ let rec cmdtable_data : (string * cmd_spec) list =
; flags= []
}
)
; ( "vtpm-create"
, {
reqd= ["vm-uuid"]
; optn= []
; help= "Create a VTPM associated with a VM."
; implementation= No_fd Cli_operations.VTPM.create
; flags= []
}
)
; ( "vtpm-destroy"
, {
reqd= ["uuid"]
; optn= []
; help= "Destroy a VTPM"
; implementation= No_fd Cli_operations.VTPM.destroy
; flags= []
}
)
]

let cmdtable : (string, cmd_spec) Hashtbl.t = Hashtbl.create 50
Expand Down
25 changes: 25 additions & 0 deletions ocaml/xapi-cli-server/cli_operations.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1287,6 +1287,10 @@ let gen_cmds rpc session_id =
]
rpc session_id
)
; Client.VTPM.(
mk get_all_records_where get_by_uuid vtpm_record "vtpm" []
["uuid"; "vm"; "profile"] rpc session_id
)
]

let message_create (_ : printer) rpc session_id params =
Expand Down Expand Up @@ -7836,3 +7840,24 @@ module Repository = struct
Client.Repository.set_gpgkey_path ~rpc ~session_id ~self:ref
~value:gpgkey_path
end

module VTPM = struct
let create printer rpc session_id params =
let vm_uuid = List.assoc "vm-uuid" params in
let vM = Client.VM.get_by_uuid ~rpc ~session_id ~uuid:vm_uuid in
let is_unique =
match List.assoc_opt "is_unique" params with
| Some value ->
bool_of_string "is_unique" value
| None ->
false
in
let ref = Client.VTPM.create ~rpc ~session_id ~vM ~is_unique in
let uuid = Client.VTPM.get_uuid ~rpc ~session_id ~self:ref in
printer (Cli_printer.PList [uuid])

let destroy _ rpc session_id params =
let uuid = List.assoc "uuid" params in
let ref = Client.VTPM.get_by_uuid ~rpc ~session_id ~uuid in
Client.VTPM.destroy ~rpc ~session_id ~self:ref
end
38 changes: 38 additions & 0 deletions ocaml/xapi-cli-server/records.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2519,6 +2519,9 @@ let vm_record rpc session_id vm =
(x ()).API.vM_pending_guidances
)
()
; make_field ~name:"vtpm"
~get:(fun () -> get_uuids_from_refs (x ()).API.vM_VTPMs)
()
]
}

Expand Down Expand Up @@ -5146,3 +5149,38 @@ let repository_record rpc session_id repository =
()
]
}

let vtpm_record rpc session_id vtpm =
let _ref = ref vtpm in
let empty_record =
ToGet (fun () -> Client.VTPM.get_record ~rpc ~session_id ~self:!_ref)
in
let record = ref empty_record in
let x () = lzy_get record in
{
setref=
(fun r ->
_ref := r ;
record := empty_record
)
; setrefrec=
(fun (a, b) ->
_ref := a ;
record := Got b
)
; record= x
; getref= (fun () -> !_ref)
; fields=
[
make_field ~name:"uuid" ~get:(fun () -> (x ()).API.vTPM_uuid) ()
; make_field ~name:"vm"
~get:(fun () -> get_uuid_from_ref (x ()).API.vTPM_VM)
()
; make_field ~name:"is_unique"
~get:(fun () -> string_of_bool (x ()).API.vTPM_is_unique)
()
; make_field ~name:"is_protected"
~get:(fun () -> string_of_bool (x ()).API.vTPM_is_protected)
()
]
}
4 changes: 4 additions & 0 deletions ocaml/xapi-consts/api_errors.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1281,3 +1281,7 @@ let dynamic_memory_control_unavailable = "DYNAMIC_MEMORY_CONTROL_UNAVAILABLE"
let apply_livepatch_failed = "APPLY_LIVEPATCH_FAILED"

let update_guidance_changed = "UPDATE_GUIDANCE_CHANGED"

(* VTPMs *)

let vtpm_max_amount_reached = "VTPM_MAX_AMOUNT_REACHED"
19 changes: 19 additions & 0 deletions ocaml/xapi-guard/src/main.ml
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,30 @@ let depriv_destroy dbg gid path =
D.debug "[%s] stopped server for gid %d and removed socket" dbg gid ;
Lwt.return_unit

let vtpm_set_contents dbg vtpm_uuid contents =
let open Xen_api_lwt_unix in
let open Lwt.Syntax in
let uuid = Uuidm.to_string vtpm_uuid in
D.debug "[%s] saving vTPM contents for %s" dbg uuid ;
ret
@@ let* self = Varstored_interface.with_xapi @@ VTPM.get_by_uuid ~uuid in
Varstored_interface.with_xapi @@ VTPM.set_contents ~self ~contents

let vtpm_get_contents _dbg vtpm_uuid =
let open Xen_api_lwt_unix in
let open Lwt.Syntax in
let uuid = Uuidm.to_string vtpm_uuid in
ret
@@ let* self = Varstored_interface.with_xapi @@ VTPM.get_by_uuid ~uuid in
Varstored_interface.with_xapi @@ VTPM.get_contents ~self

let rpc_fn =
let module Server = Varstore_privileged_interface.RPC_API (Rpc_lwt.GenServer ()) in
(* bind APIs *)
Server.create depriv_create ;
Server.destroy depriv_destroy ;
Server.vtpm_set_contents vtpm_set_contents ;
Server.vtpm_get_contents vtpm_get_contents ;
Rpc_lwt.server Server.implementation

let process body =
Expand Down
Loading