Laszlo Ersek
2022-Jun-28 09:00 UTC
[Libguestfs] LUKS decryption with Clevis+Tang | CVE-2022-2211
Hi, * in response to this cover letter, I'm going to post four series (one for each of libguestfs-common, libguestfs, guestfs-tools, virt-v2v). These four series implement LUKS decryption with Clevis+Tang: https://bugzilla.redhat.com/show_bug.cgi?id=1809453 * The first patch in the libguestfs-common series fixes a bug that I'd found while working on the feature, and ended up receiving a CVE number (CVE-2022-2211): https://bugzilla.redhat.com/show_bug.cgi?id=2100862 This patch is an integral part of the larger Clevis+Tang feature. However, it can be backported easily to stable branches that only want the bugfix. * Correspondingly, the first patch in the libguestfs series documents the new CVE (and updates the common submodule just enough to get the CVE fix). This patch should also be easy to backport to stable branches. A later patch in the libguestfs series updates the "common" submodule checkout to the end of the libguestfs-common series. * In each of the guestfs-tools and virt-v2v series, the full "common" submodule series is consumed right in the first patch, covering both the CVE fix and the new stuff needed for the Clevis feature. Thanks, Laszlo
Richard W.M. Jones
2022-Jun-28 09:24 UTC
[Libguestfs] LUKS decryption with Clevis+Tang | CVE-2022-2211
[Adding packagers to CC for visibility.] On Tue, Jun 28, 2022 at 11:00:43AM +0200, Laszlo Ersek wrote:> Hi, > > * in response to this cover letter, I'm going to post four series (one > for each of libguestfs-common, libguestfs, guestfs-tools, virt-v2v). > These four series implement LUKS decryption with Clevis+Tang: > > https://bugzilla.redhat.com/show_bug.cgi?id=1809453 > > * The first patch in the libguestfs-common series fixes a bug that I'd > found while working on the feature, and ended up receiving a CVE number > (CVE-2022-2211): > > https://bugzilla.redhat.com/show_bug.cgi?id=2100862 > > This patch is an integral part of the larger Clevis+Tang feature. > However, it can be backported easily to stable branches that only want > the bugfix. > > * Correspondingly, the first patch in the libguestfs series documents > the new CVE (and updates the common submodule just enough to get the CVE > fix). This patch should also be easy to backport to stable branches. > > A later patch in the libguestfs series updates the "common" submodule > checkout to the end of the libguestfs-common series. > > * In each of the guestfs-tools and virt-v2v series, the full "common" > submodule series is consumed right in the first patch, covering both the > CVE fix and the new stuff needed for the Clevis feature. > > Thanks, > Laszlo > _______________________________________________ > Libguestfs mailing list > Libguestfs at redhat.com > https://listman.redhat.com/mailman/listinfo/libguestfs-- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming and virtualization blog: http://rwmj.wordpress.com nbdkit - Flexible, fast NBD server with plugins https://gitlab.com/nbdkit/nbdkit
Laszlo Ersek
2022-Jun-28 11:49 UTC
[Libguestfs] [libguestfs-common PATCH 00/12] LUKS decryption with Clevis+Tang | CVE-2022-2211
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1809453
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2100862
Please refer to the parent cover letter
<https://listman.redhat.com/archives/libguestfs/2022-June/029274.html>
regarding the relationship between the CVE fix and the larger series.
The first four patches are bugfixes (of varying importance).
The rest are refactorings and feature-let additions, intermixed as
needed.
Thanks,
Laszlo
Laszlo Ersek (12):
options: fix buffer overflow in get_keys() [CVE-2022-2211]
options: fix UUID comparison logic bug in get_keys()
mltools/tools_utils: remove unused function "key_store_to_cli"
mltools/tools_utils: allow multiple "--key" options for OCaml tools
too
options: replace NULL-termination with number-of-elements in
get_keys()
options: wrap each passphrase from get_keys() into a struct
options: add back-end for LUKS decryption with Clevis+Tang
options: introduce selector tpe "key_clevis"
options: generalize "--key" selector parsing for C-language
utilities
mltools/tools_utils: generalize "--key" selector parsing for OCaml
utils
options, mltools/tools_utils: parse "--key ID:clevis" options
options, mltools/tools_utils: add helper for network dependency
mltools/tools_utils-c.c | 47 ++++---
mltools/tools_utils.ml | 51 ++++----
mltools/tools_utils.mli | 12 +-
options/decrypt.c | 24 ++--
options/key-option.pod | 9 ++
options/keys.c | 130 ++++++++++++++------
options/options.h | 19 ++-
7 files changed, 195 insertions(+), 97 deletions(-)
--
2.19.1.3.g30247aa5d201
Laszlo Ersek
2022-Jun-28 11:49 UTC
[Libguestfs] [libguestfs-common PATCH 01/12] options: fix buffer overflow in get_keys() [CVE-2022-2211]
When calculating the greatest possible number of matching keys in
get_keys(), the current expression
MIN (1, ks->nr_keys)
is wrong -- it will return at most 1.
If all "nr_keys" keys match however, then we require
"nr_keys" non-NULL
entries in the result array; in other words, we need
MAX (1, ks->nr_keys)
(The comment just above the expression is correct; the code is wrong.)
This buffer overflow is easiest to trigger in those guestfs tools that
parse the "--key" option in C; that is, with "OPTION_key".
For example,
the command
$ virt-cat $(seq -f '--key /dev/sda2:key:%g' 200) -d DOMAIN
/no-such-file
which passes 200 (different) passphrases for the LUKS-encrypted block
device "/dev/sda2", crashes with a SIGSEGV.
(
The buffer overflow is possible to trigger in OCaml-language tools as
well; that is, those that call "create_standard_options" with
~key_opts:true.
Triggering the problem that way is less trivial. The reason is that when
the OCaml tools parse the "--key" options, they de-duplicate the
options
first, based on the device identifier.
Thus, in theory, this de-duplication masks the issue, as (one would
think) only one "--key" option could belong to a single device, and
therefore the buffer overflow would not be triggered in practice.
This is not the case however: the de-duplication does not collapse keys
that are provided for the same device, but use different identifier
types (such as pathname of device node versus LUKS UUID) -- in that
situation, two entries in the keystore will match the device, and the
terminating NULL entry will not be present once get_keys() returns. In
this scenario, we don't have an out-of-bounds write, but an
out-of-bounds read, in decrypt_mountables() [options/decrypt.c].
There is *yet another* bug in get_keys() though that undoes the above
"masking". The "uuid" parameter of get_keys() may be NULL
(for example
when the device to decrypt uses BitLocker and not LUKS). When this
happens, get_keys() adds all keys in the keystore to the result array.
Therefore, the out-of-bounds write is easy to trigger with
OCaml-language tools as well, as long as we attempt to decrypt a
BitLocker (not LUKS) device, and we pass the "--key" options with
different device identifiers.
Subsequent patches in this series fix all of the above; this patch fixes
the security bug.
)
Rather than replacing MIN with MAX, open-code the comparison, as we first
set "len" to 1 anyway.
While at it, rework the NULL-termination such that the (len+1) addition
not go unchecked.
Fixes: c10c8baedb88e7c2988a01b70fc5f81fa8e4885c
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1809453
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2100862
Signed-off-by: Laszlo Ersek <lersek at redhat.com>
---
options/keys.c | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/options/keys.c b/options/keys.c
index 798315c2e95a..d27a7123e67e 100644
--- a/options/keys.c
+++ b/options/keys.c
@@ -126,21 +126,27 @@ read_first_line_from_file (const char *filename)
* keystore, ask the user.
*/
char **
get_keys (struct key_store *ks, const char *device, const char *uuid)
{
- size_t i, j, len;
+ size_t i, j, nmemb;
char **r;
char *s;
/* We know the returned list must have at least one element and not
* more than ks->nr_keys.
*/
- len = 1;
- if (ks)
- len = MIN (1, ks->nr_keys);
- r = calloc (len+1, sizeof (char *));
+ nmemb = 1;
+ if (ks && ks->nr_keys > nmemb)
+ nmemb = ks->nr_keys;
+
+ /* make room for the terminating NULL */
+ if (nmemb == (size_t)-1)
+ error (EXIT_FAILURE, 0, _("size_t overflow"));
+ nmemb++;
+
+ r = calloc (nmemb, sizeof (char *));
if (r == NULL)
error (EXIT_FAILURE, errno, "calloc");
j = 0;
--
2.19.1.3.g30247aa5d201
Laszlo Ersek
2022-Jun-28 11:54 UTC
[Libguestfs] [libguestfs PATCH 0/3] LUKS decryption with Clevis+Tang | CVE-2022-2211
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1809453 Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2100862 Please refer to the parent cover letter <https://listman.redhat.com/archives/libguestfs/2022-June/029274.html> regarding the relationship between the CVE fix and the larger series. Thanks, Laszlo Laszlo Ersek (3): docs/guestfs-security: document CVE-2022-2211 introduce the "clevis_luks_unlock" API guestfish, guestmount: enable networking for "--key ID:clevis" appliance/packagelist.in | 4 ++ common | 2 +- daemon/Makefile.am | 1 + daemon/clevis-luks.c | 58 ++++++++++++++++++++ docs/guestfs-security.pod | 28 ++++++++++ fish/fish.c | 3 + fuse/guestmount.c | 4 ++ generator/actions_core.ml | 38 +++++++++++++ generator/proc_nr.ml | 1 + lib/MAX_PROC_NR | 2 +- lib/guestfs.pod | 19 +++++-- 11 files changed, 154 insertions(+), 6 deletions(-) create mode 100644 daemon/clevis-luks.c -- 2.19.1.3.g30247aa5d201
Laszlo Ersek
2022-Jun-28 11:54 UTC
[Libguestfs] [libguestfs PATCH 1/3] docs/guestfs-security: document CVE-2022-2211
Short log for the common submodule, commit range
f8de5508fe75..35b49ce142fb:
Laszlo Ersek (2):
mlcustomize: factor out pkg install/update/uninstall from guestfs-tools
options: fix buffer overflow in get_keys() [CVE-2022-2211]
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1809453
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2100862
Signed-off-by: Laszlo Ersek <lersek at redhat.com>
---
Notes:
"Commit 35b49ce142fb" needs to updated here, in both the submodule
checkout and the commit message, once the libguestfs-common series is
merged.
common | 2 +-
docs/guestfs-security.pod | 28 ++++++++++++++++++++
2 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/common b/common
index f8de5508fe75..35b49ce142fb 160000
--- a/common
+++ b/common
@@ -1 +1 @@
-Subproject commit f8de5508fe755acca99c9ab40c501d6c3e2bcb1e
+Subproject commit 35b49ce142fb906bcf91edc6a6718d28c8fca9e3
diff --git a/docs/guestfs-security.pod b/docs/guestfs-security.pod
index 9ceef5623370..efa35b29d301 100644
--- a/docs/guestfs-security.pod
+++ b/docs/guestfs-security.pod
@@ -404,10 +404,38 @@ S<C<guestfs_set_network (g, 1)>> (which is not
the default).
The libvirt backend is not affected.
The solution is to update qemu to a version containing the fix (see
L<https://lists.gnu.org/archive/html/qemu-devel/2018-06/msg01012.html>).
+=head2 CVE-2022-2211
+
+L<https://bugzilla.redhat.com/CVE-2022-2211>
+
+The C<get_keys> function in F<libguestfs-common/options/keys.c>
collects
+those I<--key> options from the command line into a new array that match
+a particular block device that's being decrypted for inspection. The
+function intends to size the result array such that potentially all
+I<--key> options, plus a terminating C<NULL> element, fit into it.
The
+code mistakenly uses the C<MIN> macro instead of C<MAX>, and
therefore
+only one element is allocated before the C<NULL> terminator.
+
+Passing precisely two I<--key ID:...> options on the command line for
+the encrypted block device C<ID> causes C<get_keys> to overwrite
the
+terminating C<NULL>, leading to an out-of-bounds read in
+C<decrypt_mountables>, file F<libguestfs-common/options/decrypt.c>.
+
+Passing more than two I<--key ID:...> options on the command line for
+the encrypted block device C<ID> causes C<get_keys> itself to
perform
+out-of-bounds writes. The most common symptom is a crash with C<SIGSEGV>
+later on.
+
+This issue affects -- broadly speaking -- all libguestfs-based utilities
+that accept I<--key>, namely: C<guestfish>, C<guestmount>,
C<virt-cat>,
+C<virt-customize>, C<virt-diff>, C<virt-edit>,
C<virt-get-kernel>,
+C<virt-inspector>, C<virt-log>, C<virt-ls>,
C<virt-sparsify>,
+C<virt-sysprep>, C<virt-tail>, C<virt-v2v>.
+
=head1 SEE ALSO
L<guestfs(3)>,
L<guestfs-internals(1)>,
L<guestfs-release-notes(1)>,
--
2.19.1.3.g30247aa5d201
Laszlo Ersek
2022-Jun-28 11:56 UTC
[Libguestfs] [guestfs-tools PATCH 0/4] LUKS decryption with Clevis+Tang
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1809453
Laszlo Ersek (4):
cat, log, ls, tail, diff, edit, insp.: set networking for "--key
ID:clevis"
get-kernel, sparsify: set networking for "--key ID:clevis"
customize: add reminder about "--key ID:clevis"
sysprep: set networking for "--key ID:clevis"
cat/cat.c | 3 +++
cat/log.c | 3 +++
cat/ls.c | 3 +++
cat/tail.c | 3 +++
common | 2 +-
customize/customize_main.ml | 7 +++++++
diff/diff.c | 8 ++++++++
edit/edit.c | 3 +++
get-kernel/get_kernel.ml | 1 +
inspector/inspector.c | 3 +++
sparsify/copying.ml | 1 +
sparsify/in_place.ml | 1 +
sysprep/main.ml | 7 +++++--
13 files changed, 42 insertions(+), 3 deletions(-)
--
2.19.1.3.g30247aa5d201
Laszlo Ersek
2022-Jun-28 11:58 UTC
[Libguestfs] [v2v PATCH] convert: document networking dependency of "--key ID:clevis"
Virt-v2v enables appliance networking already, for the sake of
"unconfigure_vmware". We now have a second use case for networking:
"--key
ID:clevis". Update the comment in the code.
(Short log for libguestfs-common commit range 9e990f3e4530..0399dea30e63:
Laszlo Ersek (12):
options: fix buffer overflow in get_keys() [CVE-2022-2211]
options: fix UUID comparison logic bug in get_keys()
mltools/tools_utils: remove unused function "key_store_to_cli"
mltools/tools_utils: allow multiple "--key" options for OCaml
tools too
options: replace NULL-termination with number-of-elements in get_keys()
options: wrap each passphrase from get_keys() into a struct
options: add back-end for LUKS decryption with Clevis+Tang
options: introduce selector tpe "key_clevis"
options: generalize "--key" selector parsing for C-language
utilities
mltools/tools_utils: generalize "--key" selector parsing for
OCaml utils
options, mltools/tools_utils: parse "--key ID:clevis" options
options, mltools/tools_utils: add helper for network dependency
).
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1809453
Signed-off-by: Laszlo Ersek <lersek at redhat.com>
---
Notes:
The submodule commit range 9e990f3e4530..0399dea30e63 needs to be
refreshed in both the commit message and the "common" hunk, once
the
libguestfs-common series is upstream.
convert/convert.ml | 3 ++-
common | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/convert/convert.ml b/convert/convert.ml
index 87fca7252ba3..17a75e3fad32 100644
--- a/convert/convert.ml
+++ b/convert/convert.ml
@@ -54,11 +54,12 @@ let rec convert dir options source g#set_memsize
(g#get_memsize () * 2);
(* Setting the number of vCPUs allows parallel mkinitrd, but make
* sure this is not too large because each vCPU consumes guest RAM.
*)
g#set_smp (min 8 (Sysconf.nr_processors_online ()));
- (* The network is only used by the unconfigure_vmware () function. *)
+ (* The network is used by the unconfigure_vmware () function, and the
"--key
+ * ID:clevis" command line options (if any). *)
g#set_network true;
List.iter (
fun { s_disk_id = i } ->
(* NB: Old virt-v2v used copyonread here, when it was using a
* qcow2 file as overlay. We MUST NOT use copyonread! It
diff --git a/common b/common
index 9e990f3e4530..0399dea30e63 160000
--- a/common
+++ b/common
@@ -1 +1 @@
-Subproject commit 9e990f3e4530df3708d176bc50e0bc68cf07d3ff
+Subproject commit 0399dea30e6353870183a07a82d05b4ec8f20ca0
--
2.19.1.3.g30247aa5d201