Laszlo Ersek
2023-May-15 17:49 UTC
[Libguestfs] [libguestfs-common PATCH 0/2] recognize "/dev/mapper/VG-LV" with "--key"
https://bugzilla.redhat.com/show_bug.cgi?id=2168506 The commit message of the second patch explains the idea. The test suites in libguestfs, guestfs-tools and virt-v2v will have to be extended so they cover this feature; I'm soon going to post the virt-v2v update. I plan to cover the libguestfs and guestfs-tools test suites later. Thanks for reviewing, Laszlo Laszlo Ersek (2): options/keys: key_store_import_key(): un-constify "key" parameter options/keys: introduce unescape_device_mapper_lvm() options/keys.c | 88 +++++++++++++++++++- options/options.h | 3 +- 2 files changed, 89 insertions(+), 2 deletions(-)
Laszlo Ersek
2023-May-15 17:49 UTC
[Libguestfs] [libguestfs-common PATCH 1/2] options/keys: key_store_import_key(): un-constify "key" parameter
The key_store_import_key() function is called from both C-language
utilities -- via key_store_add_from_selector() -- and OCaml-language ones
-- via guestfs_int_mllib_inspect_decrypt(). We currently declare the
function's second parameter as
const struct key_store_key *key
That is however a superficial, if not outright false, promise: in
key_store_import_key(), we take ownership of all three string fields
within "key", as evidenced by free_key_store(), where we free() all
three
strings. With the same effort, we might as well modify the contents of
those strings at once. Drop "const". (None of the callers care, but
let's
be honest.)
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2168506
Signed-off-by: Laszlo Ersek <lersek at redhat.com>
---
options/options.h | 3 ++-
options/keys.c | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/options/options.h b/options/options.h
index 94573ee063bb..94e8b9eef43e 100644
--- a/options/options.h
+++ b/options/options.h
@@ -169,7 +169,8 @@ extern struct matching_key *get_keys (struct key_store *ks,
const char *device,
const char *uuid, size_t *nr_matches);
extern void free_keys (struct matching_key *keys, size_t nr_matches);
extern struct key_store *key_store_add_from_selector (struct key_store *ks,
const char *selector);
-extern struct key_store *key_store_import_key (struct key_store *ks, const
struct key_store_key *key);
+extern struct key_store *key_store_import_key (struct key_store *ks,
+ struct key_store_key *key);
extern bool key_store_requires_network (const struct key_store *ks);
extern void free_key_store (struct key_store *ks);
diff --git a/options/keys.c b/options/keys.c
index 48f1bc7c7c47..bc7459749276 100644
--- a/options/keys.c
+++ b/options/keys.c
@@ -261,7 +261,7 @@ key_store_add_from_selector (struct key_store *ks, const
char *selector)
}
struct key_store *
-key_store_import_key (struct key_store *ks, const struct key_store_key *key)
+key_store_import_key (struct key_store *ks, struct key_store_key *key)
{
struct key_store_key *new_keys;
Laszlo Ersek
2023-May-15 17:49 UTC
[Libguestfs] [libguestfs-common PATCH 2/2] options/keys: introduce unescape_device_mapper_lvm()
Introduce unescape_device_mapper_lvm() for turning
/dev/mapper/VG-LV
key IDs into
/dev/VG/LV
ones, unescaping doubled hyphens to single hyphens in both VG and LV in
the process. Libguestfs uses the /dev/VG/LV format internally, for
identifying devices, but the user might want to specify the
/dev/mapper/VG-LV ID format with the "--key ID:..." options.
Call unescape_device_mapper_lvm() from key_store_import_key(). That is,
translate the ID as soon as the "--key" option is processed -- let the
keystore only know about the usual /dev/VG/LV format, for later matching.
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2168506
Signed-off-by: Laszlo Ersek <lersek at redhat.com>
---
Notes:
regcomp() must definitely allocate memory dynamically, and we
(intentionally) never free that -- we never call regfree(). I assume
valgrind will catch this as a leak, so we might have to extend
"valgrind-suppressions" in each dependent superproject. However,
I'm
unable to run "make check-valgrind" successfully in e.g. virt-v2v
even
before these patches; see also
<https://listman.redhat.com/archives/libguestfs/2023-May/031496.html>.
options/keys.c | 86 ++++++++++++++++++++
1 file changed, 86 insertions(+)
diff --git a/options/keys.c b/options/keys.c
index bc7459749276..f0164a6ed987 100644
--- a/options/keys.c
+++ b/options/keys.c
@@ -27,6 +27,7 @@
#include <errno.h>
#include <error.h>
#include <assert.h>
+#include <regex.h>
#include "guestfs.h"
@@ -260,6 +261,90 @@ key_store_add_from_selector (struct key_store *ks, const
char *selector)
return key_store_import_key (ks, &key);
}
+/* A /dev/mapper/ escaped character is:
+ * - either any character except a slash or a hyphen,
+ * - or a double hyphen.
+ *
+ * Note that parens are deliberately not included here -- they will be included
+ * in the full pattern, for making them more easily countable.
+ *
+ * Also note that the bracket expression below does not contain a range
+ * expression, therefore it should not be locale-sensitive.
+ */
+#define ESC_CH "[^-/]|--"
+
+/* Turn /dev/mapper/VG-LV into /dev/VG/LV. */
+static void
+unescape_device_mapper_lvm (char *id)
+{
+ static bool compiled;
+ int rc;
+ static regex_t regex;
+ regmatch_t match[5];
+ char *output;
+ const char *vg_start, *vg_end, *lv_start, *lv_end;
+ const char *input;
+
+ if (!compiled) {
+ /* Recognize /dev/mapper/VG-LV pathnames, where VG and LV don't contain
+ * slashes, plus any original hyphens in them are doubled for escaping.
+ */
+ static const char pattern[] = "^/dev/("
+ "mapper/"
+ "((" ESC_CH ")+)"
+ "-"
+ "((" ESC_CH ")+)"
+ ")$";
+
+ rc = regcomp (®ex, pattern, REG_EXTENDED);
+ if (rc != 0) {
+ char errbuf[256];
+
+ /* When regcomp() fails, the contents of "regex" are undefined,
so we
+ * cannot pass "regex" to regerror().
+ */
+ (void)regerror (rc, NULL, errbuf, sizeof errbuf);
+ error (EXIT_FAILURE, 0,
+ _("%s: Failed to compile pattern (%s). Please report a bug
for "
+ "libguestfs -- refer to guestfs(3) section BUGS."),
+ __func__, errbuf);
+ }
+ compiled = true;
+ }
+
+ rc = regexec (®ex, id, 5, match, 0);
+
+ /* If there's no match, just leave "id" alone. */
+ if (rc != 0)
+ return;
+
+ /* Start outputting after "/dev/". */
+ output = id + match[1].rm_so;
+ vg_start = id + match[2].rm_so;
+ vg_end = id + match[2].rm_eo;
+ lv_start = id + match[4].rm_so;
+ lv_end = id + match[4].rm_eo;
+
+ /* Each of the following two loops produces at most as many bytes as it
+ * consumes, so we unescape "id" in-place.
+ */
+ input = vg_start;
+ while (input < vg_end)
+ if ((*output++ = *input++) == '-')
+ input++;
+
+ *output++ = '/';
+
+ input = lv_start;
+ while (input < lv_end)
+ if ((*output++ = *input++) == '-')
+ input++;
+
+ *output++ = '\0';
+}
+
+#undef ESC_CH
+
struct key_store *
key_store_import_key (struct key_store *ks, struct key_store_key *key)
{
@@ -278,6 +363,7 @@ key_store_import_key (struct key_store *ks, struct
key_store_key *key)
error (EXIT_FAILURE, errno, "realloc");
ks->keys = new_keys;
+ unescape_device_mapper_lvm (key->id);
ks->keys[ks->nr_keys] = *key;
++ks->nr_keys;