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

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