Skip to content

Commit d1dd285

Browse files
authored
Merge pull request #4901 from mg12/private/marcusg/CP-41675
2 parents 8719d71 + 097dd5a commit d1dd285

File tree

6 files changed

+181
-41
lines changed

6 files changed

+181
-41
lines changed

ocaml/xapi/helpers.ml

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1959,10 +1959,24 @@ end = struct
19591959
Xapi_psr_util.load_psr_pool_secrets ()
19601960
end
19611961

1962+
let ( let@ ) f x = f x
1963+
1964+
let with_temp_out_ch ch f = finally (fun () -> f ch) (fun () -> close_out ch)
1965+
1966+
let with_temp_file ?mode prefix suffix f =
1967+
let path, channel = Filename.open_temp_file ?mode prefix suffix in
1968+
finally (fun () -> f (path, channel)) (fun () -> Unix.unlink path)
1969+
1970+
let with_temp_out_ch_of_temp_file ?mode prefix suffix f =
1971+
let@ path, channel = with_temp_file ?mode prefix suffix in
1972+
f (path, channel |> with_temp_out_ch)
1973+
19621974
module FileSys : sig
19631975
(* bash-like interface for manipulating files *)
19641976
type path = string
19651977

1978+
val realpathm : path -> path
1979+
19661980
val rmrf : ?rm_top:bool -> path -> unit
19671981

19681982
val mv : src:path -> dest:path -> unit
@@ -1973,16 +1987,24 @@ module FileSys : sig
19731987
end = struct
19741988
type path = string
19751989

1990+
let realpathm path = try Unix.readlink path with _ -> path
1991+
19761992
let rmrf ?(rm_top = true) path =
19771993
let ( // ) = Filename.concat in
19781994
let rec rm rm_top path =
1979-
let st = Unix.lstat path in
1980-
match st.Unix.st_kind with
1981-
| Unix.S_DIR ->
1982-
Sys.readdir path |> Array.iter (fun file -> rm true (path // file)) ;
1983-
if rm_top then Unix.rmdir path
1984-
| _ ->
1985-
Unix.unlink path
1995+
match Unix.lstat path with
1996+
| exception Unix.Unix_error (Unix.ENOENT, _, _) ->
1997+
() (*noop*)
1998+
| exception e ->
1999+
raise e
2000+
| st -> (
2001+
match st.Unix.st_kind with
2002+
| Unix.S_DIR ->
2003+
Sys.readdir path |> Array.iter (fun file -> rm true (path // file)) ;
2004+
if rm_top then Unix.rmdir path
2005+
| _ ->
2006+
Unix.unlink path
2007+
)
19862008
in
19872009
try rm rm_top path
19882010
with e ->

ocaml/xapi/xapi_db_upgrade.ml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,19 @@ let remove_legacy_ssl_support =
868868
)
869869
}
870870

871+
let empty_pool_uefi_certificates =
872+
{
873+
description=
874+
"empty contents of pool.uefi_certificates, as they are now provided in \
875+
RPMs"
876+
; version= (fun _ -> true)
877+
; fn=
878+
(fun ~__context ->
879+
let pool = Helpers.get_pool ~__context in
880+
Db.Pool.set_uefi_certificates ~__context ~self:pool ~value:""
881+
)
882+
}
883+
871884
let rules =
872885
[
873886
upgrade_domain_type
@@ -896,6 +909,7 @@ let rules =
896909
; upgrade_cluster_timeouts
897910
; upgrade_secrets
898911
; remove_legacy_ssl_support
912+
; empty_pool_uefi_certificates
899913
]
900914

901915
(* Maybe upgrade most recent db *)

ocaml/xapi/xapi_globs.ml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -844,7 +844,11 @@ let nbd_client_manager_script =
844844

845845
let varstore_rm = ref "/usr/bin/varstore-rm"
846846

847-
let varstore_dir = ref "/usr/share/varstored"
847+
let varstore_dir = ref "/var/lib/varstored"
848+
849+
let default_auth_dir = ref "/usr/share/varstored"
850+
851+
let override_uefi_certs = ref false
848852

849853
let disable_logging_for = ref []
850854

@@ -1395,6 +1399,12 @@ let other_options =
13951399
, (fun () -> string_of_bool !ignore_vtpm_unimplemented)
13961400
, "Do not raise errors on use-cases where VTPM codepaths are not finished."
13971401
)
1402+
; ( "override-uefi-certs"
1403+
, Arg.Set override_uefi_certs
1404+
, (fun () -> string_of_bool !override_uefi_certs)
1405+
, "Enable (true) or Disable (false) overriding location for varstored UEFI \
1406+
certificates"
1407+
)
13981408
]
13991409

14001410
(* The options can be set with the variable xapiflags in /etc/sysconfig/xapi.

ocaml/xapi/xapi_host.ml

Lines changed: 107 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2672,26 +2672,47 @@ let with_temp_file_contents ~contents f =
26722672
)
26732673
(fun () -> Sys.remove filename)
26742674

2675-
let write_uefi_certificates_to_disk ~__context ~host:_ =
2676-
if
2677-
Sys.file_exists !Xapi_globs.varstore_dir
2678-
&& Sys.is_directory !Xapi_globs.varstore_dir
2679-
then
2680-
match
2681-
Base64.decode
2682-
(Db.Pool.get_uefi_certificates ~__context
2683-
~self:(Helpers.get_pool ~__context)
2684-
)
2685-
with
2675+
let ( let@ ) f x = f x
2676+
2677+
let ( // ) = Filename.concat
2678+
2679+
let really_read_uefi_certificates_from_disk ~__context ~host:_ from_path =
2680+
let certs_files = Sys.readdir from_path |> Array.map (( // ) from_path) in
2681+
let@ temp_file, with_temp_out_ch =
2682+
Helpers.with_temp_out_ch_of_temp_file ~mode:[Open_binary]
2683+
"pool-uefi-certificates" "tar"
2684+
in
2685+
if Array.length certs_files > 0 then (
2686+
let@ temp_out_ch = with_temp_out_ch in
2687+
Tar_unix.Archive.create
2688+
(certs_files |> Array.to_list)
2689+
(temp_out_ch |> Unix.descr_of_out_channel) ;
2690+
debug "UEFI tar file %s populated from directory %s" temp_file from_path
2691+
) else
2692+
debug "UEFI tar file %s empty from directory %s" temp_file from_path ;
2693+
temp_file |> Unixext.string_of_file |> Base64.encode_string
2694+
2695+
let really_write_uefi_certificates_to_disk ~__context ~host:_ ~value =
2696+
match value with
2697+
| "" ->
2698+
(* from an existing directory *)
2699+
Sys.readdir !Xapi_globs.default_auth_dir
2700+
|> Array.iter (fun file ->
2701+
let src = !Xapi_globs.default_auth_dir // file in
2702+
let dst = !Xapi_globs.varstore_dir // file in
2703+
let@ src_fd = Unixext.with_file src [Unix.O_RDONLY] 0o400 in
2704+
let@ dst_fd =
2705+
Unixext.with_file dst
2706+
[Unix.O_WRONLY; Unix.O_CREAT; Unix.O_TRUNC]
2707+
0o644
2708+
in
2709+
debug "override_uefi_certs: copy_file %s->%s" src dst ;
2710+
ignore (Unixext.copy_file src_fd dst_fd)
2711+
)
2712+
| base64_value -> (
2713+
(* from an existing base64 tar file *)
2714+
match Base64.decode base64_value with
26862715
| Ok contents ->
2687-
(* Remove existing certs before extracting xapi ones
2688-
* to avoid a extract override issue. *)
2689-
List.iter
2690-
(fun name ->
2691-
let path = Filename.concat !Xapi_globs.varstore_dir name in
2692-
Unixext.unlink_safe path
2693-
)
2694-
["KEK.auth"; "db.auth"] ;
26952716
(* No uefi certificates, nothing to do. *)
26962717
if contents <> "" then (
26972718
with_temp_file_contents ~contents
@@ -2702,14 +2723,75 @@ let write_uefi_certificates_to_disk ~__context ~host:_ =
27022723
| Error _ ->
27032724
debug
27042725
"UEFI tar file was not extracted: it was not base64-encoded correctly"
2726+
)
2727+
2728+
let write_uefi_certificates_to_disk ~__context ~host =
2729+
let with_valid_symlink ~from_path ~to_path fn =
2730+
debug "override_uefi_certs: with_valid_symlink %s->%s" from_path to_path ;
2731+
if Helpers.FileSys.realpathm from_path <> to_path then (
2732+
Helpers.FileSys.rmrf ~rm_top:true from_path ;
2733+
Unix.symlink to_path from_path
2734+
) ;
2735+
fn from_path
2736+
in
2737+
let with_empty_dir path fn =
2738+
debug "override_uefi_certs: with_empty_dir %s" path ;
2739+
Helpers.FileSys.rmrf ~rm_top:false path ;
2740+
Unixext.mkdir_rec path 0o755 ;
2741+
fn path
2742+
in
2743+
let check_valid_uefi_certs_in path =
2744+
let uefi_certs_in_disk = path |> Helpers.FileSys.realpathm |> Sys.readdir in
2745+
(* check expected uefi certificates are present *)
2746+
["KEK.auth"; "db.auth"]
2747+
|> List.iter (fun cert ->
2748+
let log_of found =
2749+
(if found then info else error)
2750+
"check_valid_uefi_certs: %s %s in %s"
2751+
(if found then "found" else "missing")
2752+
cert path
2753+
in
2754+
uefi_certs_in_disk |> Array.mem cert |> log_of
2755+
)
2756+
in
2757+
match !Xapi_globs.override_uefi_certs with
2758+
| false ->
2759+
let@ path =
2760+
with_valid_symlink ~from_path:!Xapi_globs.varstore_dir
2761+
~to_path:!Xapi_globs.default_auth_dir
2762+
in
2763+
check_valid_uefi_certs_in path ;
2764+
if Pool_role.is_master () then
2765+
let disk_uefi_certs_tar =
2766+
really_read_uefi_certificates_from_disk ~__context ~host
2767+
!Xapi_globs.varstore_dir
2768+
in
2769+
(* synchronize read-only field with contents in disk *)
2770+
Db.Pool.set_uefi_certificates ~__context
2771+
~self:(Helpers.get_pool ~__context)
2772+
~value:disk_uefi_certs_tar
2773+
| true ->
2774+
let@ path = with_empty_dir !Xapi_globs.varstore_dir in
2775+
(* get from pool for consistent results across hosts *)
2776+
let pool_uefi_certs =
2777+
Db.Pool.get_uefi_certificates ~__context
2778+
~self:(Helpers.get_pool ~__context)
2779+
in
2780+
really_write_uefi_certificates_to_disk ~__context ~host
2781+
~value:pool_uefi_certs ;
2782+
check_valid_uefi_certs_in path
27052783

27062784
let set_uefi_certificates ~__context ~host ~value =
2707-
Db.Host.set_uefi_certificates ~__context ~self:host ~value ;
2708-
Helpers.call_api_functions ~__context (fun rpc session_id ->
2709-
Client.Client.Pool.set_uefi_certificates ~rpc ~session_id
2710-
~self:(Helpers.get_pool ~__context)
2711-
~value
2712-
)
2785+
match !Xapi_globs.override_uefi_certs with
2786+
| false ->
2787+
raise Api_errors.(Server_error (Api_errors.operation_not_allowed, [""]))
2788+
| true ->
2789+
Db.Host.set_uefi_certificates ~__context ~self:host ~value ;
2790+
Helpers.call_api_functions ~__context (fun rpc session_id ->
2791+
Client.Client.Pool.set_uefi_certificates ~rpc ~session_id
2792+
~self:(Helpers.get_pool ~__context)
2793+
~value
2794+
)
27132795

27142796
let set_iscsi_iqn ~__context ~host ~value =
27152797
if value = "" then

ocaml/xapi/xapi_pool.ml

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3588,14 +3588,22 @@ let disable_repository_proxy ~__context ~self =
35883588
)
35893589

35903590
let set_uefi_certificates ~__context ~self ~value =
3591-
Db.Pool.set_uefi_certificates ~__context ~self ~value ;
3592-
Helpers.call_api_functions ~__context (fun rpc session_id ->
3593-
List.iter
3594-
(fun host ->
3595-
Client.Host.write_uefi_certificates_to_disk ~rpc ~session_id ~host
3596-
)
3597-
(Db.Host.get_all ~__context)
3598-
)
3591+
match !Xapi_globs.override_uefi_certs with
3592+
| false ->
3593+
let msg =
3594+
"Setting UEFI certificates is not possible when override_uefi_certs is \
3595+
false"
3596+
in
3597+
raise Api_errors.(Server_error (operation_not_allowed, [msg]))
3598+
| true ->
3599+
Db.Pool.set_uefi_certificates ~__context ~self ~value ;
3600+
Helpers.call_api_functions ~__context (fun rpc session_id ->
3601+
List.iter
3602+
(fun host ->
3603+
Client.Host.write_uefi_certificates_to_disk ~rpc ~session_id ~host
3604+
)
3605+
(Db.Host.get_all ~__context)
3606+
)
35993607

36003608
let set_https_only ~__context ~self:_ ~value =
36013609
Helpers.call_api_functions ~__context (fun rpc session_id ->

scripts/xapi.conf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ igd-passthru-vendor-whitelist = 8086
7777
# Allowlist of domain name pattern in binary-url and source-url in repository
7878
# repository-domain-name-allowlist =
7979

80+
# Override the default location of RPM-provided certificates in default_auth_dir (/usr/share/varstored)
81+
# to force use of customised UEFI certificates in varstore_dir (/var/lib/varstored)
82+
# override-uefi-certs = true
83+
8084
# Paths to utilities: ############################################
8185

8286
search-path = @LIBEXECDIR@:@OPTDIR@/bin

0 commit comments

Comments
 (0)