daemon: inspect_get_windows_group_policy

Windows group policy objects (GPOs) are restrictions that can be added
by an administrator to Windows to lock down various operations.  From
our point of view the ones that matter involve restricting the ability
to inject device drivers.

Previously virt-v2v detected group policy here:

9bb2e7d470/convert/convert_windows.ml (L69)

We would like to report group policy through the libguestfs API and
tools such as virt-inspector, so move the code that is used to detect
group policy to libguestfs.  A new API is introduced that returns
whether group policy was found (only for Windows guests) during
inspection of the software registry.

Fixes: https://issues.redhat.com/browse/RHEL-125846
This commit is contained in:
Richard W.M. Jones
2025-11-03 15:47:10 +00:00
committed by rwmjones
parent 355f8a5413
commit 1db2b7837f
7 changed files with 86 additions and 1 deletions

View File

@@ -450,6 +450,13 @@ and inspect_get_windows_current_control_set root =
| None ->
failwith "not a Windows guest, or CurrentControlSet could not be determined"
and inspect_get_windows_group_policy root =
let root = search_for_root root in
match root.inspection_data.windows_group_policy with
| Some v -> v
| None ->
failwith "not a Windows guest, or software hive could not be parsed"
and inspect_is_live root = false
and inspect_is_netinst root = false

View File

@@ -288,6 +288,54 @@ and check_windows_software_registry software_hive data =
with
Not_found -> ()
);
(* If the Windows guest appears to be using group policy, since
* group policy might be used to restrict driver injection.
*
* XXX If group policy is present, it may be possible to
* remove the restriction on driver injection. Microsoft has
* an article about this:
* https://support.microsoft.com/uk-ua/help/2773300/stop-0x0000007b-error-after-you-use-a-group-policy-setting-to-prevent
* Nikolay Ivanets pointed out that in addition to that you also
* have to delete:
* HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\DeviceInstall\Restrictions
*)
let has_group_policy =
try
(* NB This is a subtly different path from CurrentVersion path
* we used above.
*)
let path = [ "Microsoft"; "Windows"; "CurrentVersion"; "Group Policy"; "History" ] in
let node = get_node h root path in
let children = Hivex.node_children h node in
let children = Array.to_list children in
let children =
List.map (fun child -> Hivex.node_name h child) children in
eprintf "check_windows_software_registry: \
found HKLM\\SOFTWARE\\%s node with children: [%s]\n"
(String.concat "\\" path)
(String.concat ", " children);
(* Just assume any children looking like "{<GUID>}" mean that
* some GPOs were installed.
*
* In future we might want to look for nodes which match:
* History\{<GUID>}\<N> where <N> is a small integer (the order
* in which policy objects were applied.
*
* For an example registry containing GPOs, see RHBZ#1219651.
* See also: https://support.microsoft.com/en-us/kb/201453
*)
let is_gpo_guid name =
let len = String.length name in
len > 3 && name.[0] = '{' &&
Char.isxdigit name.[1] && name.[len-1] = '}'
in
List.exists is_gpo_guid children
with
Not_found -> false in
data.windows_group_policy <- Some has_group_policy;
with
| Not_found ->
if verbose () then

View File

@@ -54,6 +54,7 @@ and inspection_data = {
mutable windows_software_hive : string option;
mutable windows_system_hive : string option;
mutable windows_current_control_set : string option;
mutable windows_group_policy : bool option;
mutable drive_mappings : drive_mapping list;
}
and os_type =
@@ -188,6 +189,8 @@ and string_of_inspection_data data =
data.windows_system_hive;
Option.iter (fun v -> bpf " windows_current_control_set: %s\n" v)
data.windows_current_control_set;
Option.iter (fun v -> bpf " windows_group_policy: %b\n" v)
data.windows_group_policy;
if data.drive_mappings <> [] then (
let v =
List.map (fun (a, b) -> sprintf "(%s, %s)" a b) data.drive_mappings in
@@ -289,6 +292,7 @@ let null_inspection_data = {
windows_software_hive = None;
windows_system_hive = None;
windows_current_control_set = None;
windows_group_policy = None;
drive_mappings = [];
}
let null_inspection_data () = { null_inspection_data with os_type = None }
@@ -316,6 +320,8 @@ let merge_inspection_data child parent =
merge child.windows_system_hive parent.windows_system_hive;
parent.windows_current_control_set <-
merge child.windows_current_control_set parent.windows_current_control_set;
parent.windows_group_policy <-
merge child.windows_group_policy parent.windows_group_policy;
(* This is what the old C code did, but I doubt that it's correct. *)
parent.drive_mappings <- child.drive_mappings @ parent.drive_mappings

View File

@@ -57,6 +57,7 @@ and inspection_data = {
mutable windows_software_hive : string option;
mutable windows_system_hive : string option;
mutable windows_current_control_set : string option;
mutable windows_group_policy : bool option;
mutable drive_mappings : drive_mapping list;
}
(** During inspection, this data is collected incrementally for each

View File

@@ -521,6 +521,28 @@ hive is a valid Windows Registry hive.
You can use C<guestfs_hivex_open> to read or write to the hive.
Please read L<guestfs(3)/INSPECTION> for more details.|} };
{ defaults with
name = "inspect_get_windows_group_policy"; added = (1, 57, 6);
style = RBool "hasgrouppolicy", [String (Mountable, "root")], [];
impl = OCaml "Inspect.inspect_get_windows_group_policy";
shortdesc = "return if Windows guest has group policy";
longdesc = {|This returns true if the Windows guest
has group policy. Group policy can interfere with device
driver installation, preventing libguestfs features like
driver injection from working.
Note that the presence of group policy is only an indication that
there may be a problem with driver installation. As group policy
is extremely complex and covers many different aspects of Windows
configuration, and we make no attempt to parse it, presence of
group policy should only raise a warning.
This call assumes that the guest is Windows and that the
Registry could be examined by inspection. If this is not
the case then an error is returned.
Please read L<guestfs(3)/INSPECTION> for more details.|} };
{ defaults with

View File

@@ -523,6 +523,7 @@ let proc_nr = [
518, "btrfs_scrub_full";
519, "setfiles";
520, "ntfs_chmod";
521, "inspect_get_windows_group_policy";
]
(* End of list. If adding a new entry, add it at the end of the list

View File

@@ -1 +1 @@
520
521