|
|
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 |
|