Blame SOURCES/0014-lib-Improve-security-of-in-out-sockets-when-running-.patch

0ee30e
From 6ca02e37d72a81e7e32d4d3eef24d8a0abe3deb2 Mon Sep 17 00:00:00 2001
0ee30e
From: "Richard W.M. Jones" <rjones@redhat.com>
0ee30e
Date: Tue, 22 Mar 2022 13:53:41 +0000
0ee30e
Subject: [PATCH] lib: Improve security of in/out sockets when running virt-v2v
0ee30e
 as root
0ee30e
MIME-Version: 1.0
0ee30e
Content-Type: text/plain; charset=UTF-8
0ee30e
Content-Transfer-Encoding: 8bit
0ee30e
0ee30e
When using the libvirt backend and running as root, libvirt will run
0ee30e
qemu as a non-root user (eg. qemu:qemu).  The v2v directory stores NBD
0ee30e
endpoints that qemu must be able to open and so we set the directory
0ee30e
to mode 0711.  Unfortunately this permits any non-root user to open
0ee30e
the sockets (since, by design, they have predictable names within the
0ee30e
directory).
0ee30e
0ee30e
Additionally we were setting the sockets themselves to 0777 mode.
0ee30e
0ee30e
Instead of using directory permissions, change the owner of the
0ee30e
directory and sockets to precisely give access to the qemu user and no
0ee30e
one else.
0ee30e
0ee30e
Reported-by: Xiaodai Wang
0ee30e
Thanks: Dr David Gilbert, Daniel Berrangé, Laszlo Ersek
0ee30e
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2066773
0ee30e
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
0ee30e
(cherry picked from commit 4e7f206843735ba24e2034f694a214ef057ee139)
0ee30e
---
0ee30e
 lib/nbdkit.ml  |  3 ++-
0ee30e
 lib/qemuNBD.ml |  3 ++-
0ee30e
 lib/utils.ml   | 47 +++++++++++++++++++++++++++++++++++++++++++++--
0ee30e
 lib/utils.mli  | 11 +++++++++++
0ee30e
 4 files changed, 60 insertions(+), 4 deletions(-)
0ee30e
0ee30e
diff --git a/lib/nbdkit.ml b/lib/nbdkit.ml
0ee30e
index 85621775..9ee6f39c 100644
0ee30e
--- a/lib/nbdkit.ml
0ee30e
+++ b/lib/nbdkit.ml
0ee30e
@@ -205,6 +205,7 @@ If the messages above are not sufficient to diagnose the problem then add the 
0ee30e
   (* Set the regular Unix permissions, in case nbdkit is
0ee30e
    * running as another user.
0ee30e
    *)
0ee30e
-  chmod socket 0o777;
0ee30e
+  chown_for_libvirt_rhbz_1045069 socket;
0ee30e
+  chmod socket 0o700;
0ee30e
 
0ee30e
   socket, pid
0ee30e
diff --git a/lib/qemuNBD.ml b/lib/qemuNBD.ml
0ee30e
index 54139ce0..2c999b9f 100644
0ee30e
--- a/lib/qemuNBD.ml
0ee30e
+++ b/lib/qemuNBD.ml
0ee30e
@@ -150,7 +150,8 @@ If the messages above are not sufficient to diagnose the problem then add the 
0ee30e
   (* Set the regular Unix permissions, in case qemu is
0ee30e
    * running as another user.
0ee30e
    *)
0ee30e
-  chmod socket 0o777;
0ee30e
+  chown_for_libvirt_rhbz_1045069 socket;
0ee30e
+  chmod socket 0o700;
0ee30e
 
0ee30e
   (* We don't need the PID file any longer. *)
0ee30e
   unlink pidfile;
0ee30e
diff --git a/lib/utils.ml b/lib/utils.ml
0ee30e
index 876a44c6..7116a4f9 100644
0ee30e
--- a/lib/utils.ml
0ee30e
+++ b/lib/utils.ml
0ee30e
@@ -147,6 +147,50 @@ let backend_is_libvirt () =
0ee30e
   let backend = fst (String.split ":" backend) in
0ee30e
   backend = "libvirt"
0ee30e
 
0ee30e
+let rec chown_for_libvirt_rhbz_1045069 file =
0ee30e
+  let running_as_root = Unix.geteuid () = 0 in
0ee30e
+  if running_as_root && backend_is_libvirt () then (
0ee30e
+    try
0ee30e
+      let user = Option.default "qemu" (libvirt_qemu_user ()) in
0ee30e
+      let uid =
0ee30e
+        if String.is_prefix user "+" then
0ee30e
+          int_of_string (String.sub user 1 (String.length user - 1))
0ee30e
+        else
0ee30e
+          (Unix.getpwnam user).pw_uid in
0ee30e
+      debug "setting owner of %s to %d:root" file uid;
0ee30e
+      Unix.chown file uid 0
0ee30e
+    with
0ee30e
+    | exn -> (* Print exception, but continue. *)
0ee30e
+       debug "could not set owner of %s: %s"
0ee30e
+         file (Printexc.to_string exn)
0ee30e
+  )
0ee30e
+
0ee30e
+(* Get the local user that libvirt uses to run qemu when we are
0ee30e
+ * running as root.  This is returned as an optional string
0ee30e
+ * containing the username.  The username might be "+NNN"
0ee30e
+ * meaning a numeric UID.
0ee30e
+ * https://listman.redhat.com/archives/libguestfs/2022-March/028450.html
0ee30e
+ *)
0ee30e
+and libvirt_qemu_user =
0ee30e
+  let user =
0ee30e
+    lazy (
0ee30e
+      let conn = Libvirt.Connect.connect_readonly () in
0ee30e
+      let xml = Libvirt.Connect.get_capabilities conn in
0ee30e
+      let doc = Xml.parse_memory xml in
0ee30e
+      let xpathctx = Xml.xpath_new_context doc in
0ee30e
+      let expr =
0ee30e
+        "//secmodel[./model=\"dac\"]/baselabel[@type=\"kvm\"]/text()" in
0ee30e
+      let uid_gid = Xpath_helpers.xpath_string xpathctx expr in
0ee30e
+      match uid_gid with
0ee30e
+      | None -> None
0ee30e
+      | Some uid_gid ->
0ee30e
+         (* The string will be something like "+107:+107", return the
0ee30e
+          * UID part.
0ee30e
+          *)
0ee30e
+         Some (fst (String.split ":" uid_gid))
0ee30e
+    ) in
0ee30e
+  fun () -> Lazy.force user
0ee30e
+
0ee30e
 (* When using the SSH driver in qemu (currently) this requires
0ee30e
  * ssh-agent authentication.  Give a clear error if this hasn't been
0ee30e
  * set up (RHBZ#1139973).  This might improve if we switch to libssh1.
0ee30e
@@ -159,8 +203,7 @@ let error_if_no_ssh_agent () =
0ee30e
 (* Create the directory containing inX and outX sockets. *)
0ee30e
 let create_v2v_directory () =
0ee30e
   let d = Mkdtemp.temp_dir "v2v." in
0ee30e
-  let running_as_root = Unix.geteuid () = 0 in
0ee30e
-  if running_as_root then Unix.chmod d 0o711;
0ee30e
+  chown_for_libvirt_rhbz_1045069 d;
0ee30e
   On_exit.rmdir d;
0ee30e
   d
0ee30e
 
0ee30e
diff --git a/lib/utils.mli b/lib/utils.mli
0ee30e
index c571cca5..d431e21f 100644
0ee30e
--- a/lib/utils.mli
0ee30e
+++ b/lib/utils.mli
0ee30e
@@ -61,6 +61,17 @@ val qemu_img_supports_offset_and_size : unit -> bool
0ee30e
 val backend_is_libvirt : unit -> bool
0ee30e
 (** Return true iff the current backend is libvirt. *)
0ee30e
 
0ee30e
+val chown_for_libvirt_rhbz_1045069 : string -> unit
0ee30e
+(** If running and root, and if the backend is libvirt, libvirt
0ee30e
+    will run qemu as a non-root user.  This prevents access
0ee30e
+    to root-owned files and directories.  To fix this, provide
0ee30e
+    a function to chown things we might need to qemu:root so
0ee30e
+    qemu can access them.  Note that root normally ignores
0ee30e
+    permissions so can still access the resource.
0ee30e
+
0ee30e
+    This is best-effort.  If something fails then we carry
0ee30e
+    on and hope for the best. *)
0ee30e
+
0ee30e
 val error_if_no_ssh_agent : unit -> unit
0ee30e
 
0ee30e
 val create_v2v_directory : unit -> string
0ee30e
-- 
0ee30e
2.31.1
0ee30e