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

vTPM state storage v0 #4730

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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
42 changes: 42 additions & 0 deletions ocaml/xapi-idl/lib/uuidm_rpc_type.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
module Uuidm = struct
Copy link
Member

Choose a reason for hiding this comment

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

I recommend changing the number in the quality gate, maintaining the corresponding mli seems to much of a headache.

include Uuidm

(** Validate UUIDs by converting them to Uuidm.t in the API *)
let typ_of =
Rpc.Types.Abstract
{
aname= "uuid"
; test_data= [Uuidm.v4_gen (Random.get_state ()) ()]
; rpc_of= (fun t -> Rpc.String (Uuidm.to_string t))
; of_rpc=
(function
| Rpc.String s -> (
match Uuidm.of_string s with
| Some uuid ->
Ok uuid
| None ->
Error
(`Msg
(Printf.sprintf "typ_of_vm_uuid: not a valid UUID: %s" s)
)
)
| r ->
Error
(`Msg
(Printf.sprintf
"typ_of_vm_uuid: expected rpc string but got %s"
(Rpc.to_string r)
)
)
)
}

let t_of_sexp sexp =
match sexp |> Sexplib.Std.string_of_sexp |> Uuidm.of_string with
| None ->
Sexplib.Conv.of_sexp_error "not a UUID" sexp
| Some u ->
u

let sexp_of_t t = t |> Uuidm.to_string |> Sexplib.Std.sexp_of_string
end
11 changes: 11 additions & 0 deletions ocaml/xapi-idl/lib/uuidm_rpc_type.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module Uuidm : sig
type t = Uuidm.t

include module type of Uuidm with type t := t

val typ_of : t Rpc.Types.typ

val t_of_sexp : Sexplib.Sexp.t -> t

val sexp_of_t : t -> Sexplib.Sexp.t
end
50 changes: 16 additions & 34 deletions ocaml/xapi-idl/varstore/privileged/varstore_privileged_interface.ml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

open Rpc
open Idl
module Uuidm = Uuidm_rpc_type.Uuidm

let service_name = "xapi_depriv"

Expand All @@ -34,42 +35,10 @@ module E = Error.Make (struct
let internal_error_of e = Some (InternalError (Printexc.to_string e))
end)

module Uuidm = struct
include Uuidm

(** Validate UUIDs by converting them to Uuidm.t in the API *)
let typ_of =
Rpc.Types.Abstract
{
aname= "uuid"
; test_data= [Uuidm.v4_gen (Random.get_state ()) ()]
; rpc_of= (fun t -> Rpc.String (Uuidm.to_string t))
; of_rpc=
(function
| Rpc.String s -> (
match Uuidm.of_string s with
| Some uuid ->
Ok uuid
| None ->
Error
(`Msg
(Printf.sprintf "typ_of_vm_uuid: not a valid UUID: %s" s)
)
)
| r ->
Error
(`Msg
(Printf.sprintf
"typ_of_vm_uuid: expected rpc string but got %s"
(Rpc.to_string r)
)
)
)
}
end

type vm_uuid = Uuidm.t [@@deriving rpcty]

type vtpm_uuid = Uuidm.t [@@deriving rpcty]

module RPC_API (R : RPC) = struct
open R

Expand Down Expand Up @@ -120,4 +89,17 @@ module RPC_API (R : RPC) = struct
declare "destroy"
["Stop listening on sockets for the specified group"]
(debug_info_p @-> gid_p @-> path_p @-> returning unit_p err)

let vtpm_uuid_p =
Param.mk ~name:"vtpm_uuid" ~description:["VTPM UUID"] vtpm_uuid

let string_p = Param.mk Types.string

let vtpm_set_contents =
declare "vtpm_set_contents" ["Set vTPM contents blob"]
(debug_info_p @-> vtpm_uuid_p @-> string_p @-> returning unit_p err)

let vtpm_get_contents =
declare "vtpm_get_contents" ["Get vTPM contents blob"]
(debug_info_p @-> vtpm_uuid_p @-> returning string_p err)
end
3 changes: 2 additions & 1 deletion ocaml/xapi-idl/xen/xenops_types.ml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
open Sexplib.Std
open Xcp_pci
open Uuidm_rpc_type

module TopLevel = struct
type power_state = Running | Halted | Suspended | Paused
Expand Down Expand Up @@ -77,7 +78,7 @@ module Vm = struct

let default_firmware = Bios [@@deriving rpcty]

type tpm = Vtpm [@@deriving rpcty, sexp]
type tpm = Vtpm of Uuidm.t [@@deriving rpcty, sexp]

type hvm_info = {
hap: bool [@default true]
Expand Down
38 changes: 23 additions & 15 deletions ocaml/xapi/xapi_xenops.ml
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ let is_boot_file_whitelisted filename =
(* avoid ..-style attacks and other weird things *)
&& safe_str filename

let builder_of_vm ~__context (_, vm) timeoffset pci_passthrough vgpu =
let builder_of_vm ~__context (vmref, vm) timeoffset pci_passthrough vgpu =
let open Vm in
let video_mode =
if vgpu then
Expand Down Expand Up @@ -386,20 +386,28 @@ let builder_of_vm ~__context (_, vm) timeoffset pci_passthrough vgpu =
warn "QEMU stub domains are no longer implemented" ;

let tpm_of_vm () =
if bool vm.API.vM_platform false "vtpm" then (
if vm.API.vM_VTPMs = [] then (
let ref () = Ref.make () in
let uuid () = Uuid.(to_string (make_uuid ())) in
let profile = [] in
let other_config = [] in
let contents = ref () in
Db.Secret.create ~__context ~ref:contents ~uuid:(uuid ()) ~value:""
~other_config ;
Db.VTPM.create ~__context ~ref:(ref ()) ~uuid:(uuid ()) ~vM:vmref
~profile ~contents
) ;
Some Xenops_interface.Vm.Vtpm
) else
if bool vm.API.vM_platform false "vtpm" then
let uuid =
match vm.API.vM_VTPMs with
| [] ->
let ref () = Ref.make () in
let uuid () = Uuid.(to_string (make ())) in
let profile = [] in
let other_config = [] in
let contents = ref () in
Db.Secret.create ~__context ~ref:contents ~uuid:(uuid ())
~value:"" ~other_config ;
let vtpm_uuid = uuid () in
Db.VTPM.create ~__context ~ref:(ref ()) ~uuid:vtpm_uuid ~vM:vmref
~profile ~contents ;
vtpm_uuid
| [self] ->
Db.VTPM.get_uuid ~__context ~self
| _ :: _ :: _ ->
failwith "Multiple vTPMs are not supported"
in
Some (Xenops_interface.Vm.Vtpm (Uuidm.of_string uuid |> Option.get))
else
None
in

Expand Down
5 changes: 3 additions & 2 deletions ocaml/xenopsd/cli/xn.ml
Original file line number Diff line number Diff line change
Expand Up @@ -605,8 +605,9 @@ let add' _copts x () =
; firmware= Xenops_types.Vm.default_firmware
; tpm=
( match find_opt _vtpm with
| Some id when bool id ->
Some Vtpm
| Some id ->
Some
(Vtpm (string id |> Uuidm.of_string |> Option.get))
| _ ->
None
)
Expand Down
5 changes: 5 additions & 0 deletions ocaml/xenopsd/lib/resources.ml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ let qemu_system_i386 = ref "qemu-system-i386"

let upstream_compat_qemu_dm_wrapper = ref "qemu-wrapper"

let swtpm_wrapper = ref "swtpm-wrapper"

let chgrp = ref "chgrp"

let modprobe = ref "/usr/sbin/modprobe"
Expand Down Expand Up @@ -77,6 +79,9 @@ let pvinpvh_guests =
)
]

let vtpm_guests =
[(X_OK, "swtpm-wrapper", swtpm_wrapper, "path to swtpm-wrapper")]

(* libvirt xc *)
let network_configuration =
[(R_OK, "network-conf", network_conf, "path to the network backend switch")]
Expand Down
7 changes: 7 additions & 0 deletions ocaml/xenopsd/lib/suspend_image.ml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ type header_type =
| Qemu_xen
| Demu
| Varstored
| Swtpm
| End_of_image

exception Invalid_header_type
Expand All @@ -83,6 +84,8 @@ let header_type_of_int64 = function
Ok Demu
| 0x0f11L ->
Ok Varstored
| 0x0f12L ->
Ok Swtpm
| 0xffffL ->
Ok End_of_image
| _ ->
Expand All @@ -105,6 +108,8 @@ let int64_of_header_type = function
0x0f10L
| Varstored ->
0x0f11L
| Swtpm ->
0x0f12L
| End_of_image ->
0xffffL

Expand All @@ -129,6 +134,8 @@ let string_of_header h =
s "vGPU save record (record length=%Ld)" len
| Varstored, len ->
s "varstored save record (record length=%Ld)" len
| Swtpm, len ->
s "swtpm save record (record length=%Ld)" len
| End_of_image, _ ->
s "Suspend image footer"

Expand Down
1 change: 1 addition & 0 deletions ocaml/xenopsd/lib/suspend_image.mli
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type header_type =
| Qemu_xen
| Demu
| Varstored
| Swtpm
| End_of_image

type format = Structured | Legacy
Expand Down
2 changes: 2 additions & 0 deletions ocaml/xenopsd/lib/xenops_sandbox.ml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ end
module type SANDBOX = sig
val create : domid:int -> vm_uuid:string -> Chroot.Path.t -> string

val chroot : domid:int -> vm_uuid:string -> Chroot.t

val start :
string
-> vm_uuid:string
Expand Down
5 changes: 5 additions & 0 deletions ocaml/xenopsd/lib/xenops_sandbox.mli
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ module type SANDBOX = sig
[domid] inside the chroot for [domid] and returns the absolute path to it
outside the chroot *)

val chroot : domid:int -> vm_uuid:string -> Chroot.t
(** [chroot ~domid ~vm_uuid] returns the chroot for [domid] and [vm_uuid].
The chroot may not necessarily exist yet.
*)

val start :
string
-> vm_uuid:string
Expand Down
1 change: 1 addition & 0 deletions ocaml/xenopsd/scripts/make-custom-xenopsd.conf
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ qemu-dm-wrapper=${LIBEXECDIR}/qemu-dm-wrapper
setup-vif-rules=${LIBEXECDIR}/setup-vif-rules
sockets-group=$group
qemu-wrapper=${QEMU_WRAPPER_DIR}/qemu-wrapper
swtpm-wrapper=${QEMU_WRAPPER_DIR}/qemu-wrapper

disable-logging-for=http
# Workaround xenopsd bug #45
Expand Down
3 changes: 3 additions & 0 deletions ocaml/xenopsd/suspend_image_viewer/suspend_image_viewer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ let parse_layout fd =
| Varstored, len ->
Io.read fd (Io.int_of_int64_exn len) |> ignore ;
aux (h :: acc)
| Swtpm, len ->
Io.read fd (Io.int_of_int64_exn len) |> ignore ;
aux (h :: acc)
| End_of_image, _ ->
return (h :: acc)
| Libxl, _ ->
Expand Down
2 changes: 1 addition & 1 deletion ocaml/xenopsd/test/test.ml
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ let create_vm vmid =
; qemu_disk_cmdline= false
; qemu_stubdom= false
; firmware= Bios
; tpm= Some Vtpm
; tpm= None
}
in
{
Expand Down
Loading