Blob Blame History Raw
From f8a041846bd596276dc37cabd217d5f37312256c Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Mon, 7 Sep 2015 17:18:41 +0100
Subject: [PATCH] v2v: windows: Warn if Group Policy or AV software may result
 in 7B boot failure (RHBZ#1260689).

Check if the Windows guest has Group Policy Objects installed, or one
of several popular pieces of anti-virus software.  If we are
installing a virtio block driver, then experience has shown this may
cause a 7B boot failure.

Print a warning when this combination happens.

The warnings look like this:

[  19.9] Converting Windows Server 2008 R2 Enterprise to run on KVM
virt-v2v: warning: this guest has Windows Group Policy Objects (GPO) and a
new virtio block device driver was installed.  In some circumstances, Group
Policy may prevent new drivers from working (resulting in a 7B boot error).
 If this happens, try disabling Group Policy before doing the conversion.
virt-v2v: warning: this guest has Anti-Virus (AV) software and a new virtio
block device driver was installed.  In some circumstances, AV may prevent
new drivers from working (resulting in a 7B boot error).  If this happens,
try disabling AV before doing the conversion.
virt-v2v: This guest has virtio drivers installed.

(cherry picked from commit 8e28d6b18860f8ff4e02489317749a723fa145ab)
---
 mllib/common_utils.ml  |  6 +++++
 mllib/common_utils.mli |  2 ++
 v2v/convert_windows.ml | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 68 insertions(+)

diff --git a/mllib/common_utils.ml b/mllib/common_utils.ml
index 8f0f065..198a5fb 100644
--- a/mllib/common_utils.ml
+++ b/mllib/common_utils.ml
@@ -58,6 +58,12 @@ let le32_of_int i =
   String.unsafe_set s 3 (Char.unsafe_chr (Int64.to_int c3));
   s
 
+let isxdigit = function
+  | '0'..'9' -> true
+  | 'a'..'f' -> true
+  | 'A'..'F' -> true
+  | _ -> false
+
 type wrap_break_t = WrapEOS | WrapSpace | WrapNL
 
 let rec wrap ?(chan = stdout) ?(indent = 0) str =
diff --git a/mllib/common_utils.mli b/mllib/common_utils.mli
index ad2b4c7..ed7de7f 100644
--- a/mllib/common_utils.mli
+++ b/mllib/common_utils.mli
@@ -32,6 +32,8 @@ val div_roundup64 : int64 -> int64 -> int64
 val int_of_le32 : string -> int64
 val le32_of_int : int64 -> string
 
+val isxdigit : char -> bool
+
 val wrap : ?chan:out_channel -> ?indent:int -> string -> unit
 (** Wrap text. *)
 
diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml
index e3d3a39..36cf8c1 100644
--- a/v2v/convert_windows.ml
+++ b/v2v/convert_windows.ml
@@ -41,6 +41,14 @@ module G = Guestfs
 
 type ('a, 'b) maybe = Either of 'a | Or of 'b
 
+(* Antivirus regexps that match on inspect.i_apps.app2_name fields. *)
+let av_rex =
+  let alternatives = [
+    "virus"; (* generic *)
+    "Kaspersky"; "McAfee"; "Norton"; "Sophos";
+  ] in
+  Str.regexp_case_fold (String.concat "\\|" alternatives)
+
 let convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source =
   (* Get the data directory. *)
   let virt_tools_data_dir =
@@ -103,6 +111,47 @@ let convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source =
   (*----------------------------------------------------------------------*)
   (* Inspect the Windows guest. *)
 
+  (* Warn if Windows guest appears to be using group policy. *)
+  let has_group_policy =
+    let check_group_policy root =
+      try
+        let node =
+          get_node root
+                   ["Microsoft"; "Windows"; "CurrentVersion"; "Group Policy";
+                    "History"] in
+        let children = g#hivex_node_children node in
+        let children = Array.to_list children in
+        let children =
+          List.map (fun { G.hivex_node_h = h } -> g#hivex_node_name h)
+                   children in
+        (* 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] = '{' && isxdigit name.[1] && name.[len-1] = '}'
+        in
+        List.exists is_gpo_guid children
+      with
+        Not_found -> false
+    in
+    with_hive "software" ~write:false check_group_policy in
+
+  (* Warn if Windows guest has AV installed. *)
+  let has_antivirus =
+    let check_app { G.app2_name = name } =
+      try ignore (Str.search_forward av_rex name 0); true
+      with Not_found -> false
+    in
+    List.exists check_app inspect.i_apps in
+
   (* Open the software hive (readonly) and find the Xen PV uninstaller,
    * if it exists.
    *)
@@ -488,6 +537,17 @@ echo uninstalling Xen PV driver
 
   fix_ntfs_heads ();
 
+  (* Warn if installation of virtio block drivers might conflict with
+   * group policy or AV software causing a boot 0x7B error (RHBZ#1260689).
+   *)
+  let () =
+    if block_driver = Virtio_blk then (
+      if has_group_policy then
+        warning ~prog (f_"this guest has Windows Group Policy Objects (GPO) and a new virtio block device driver was installed.  In some circumstances, Group Policy may prevent new drivers from working (resulting in a 7B boot error).  If this happens, try disabling Group Policy before doing the conversion.");
+      if has_antivirus then
+        warning ~prog (f_"this guest has Anti-Virus (AV) software and a new virtio block device driver was installed.  In some circumstances, AV may prevent new drivers from working (resulting in a 7B boot error).  If this happens, try disabling AV before doing the conversion.");
+    ) in
+
   (* Return guest capabilities. *)
   let guestcaps = {
     gcaps_block_bus = block_driver;
-- 
1.8.3.1