On Wed, Aug 31, 2022 at 13:41:00 -0500, Jonathon Jongsma wrote:
Rather than passing passwords and cookies (which could contain
passwords) to nbdkit via commandline arguments, use the alternate format
that nbdkit supports where we can specify a file descriptor which nbdkit
will read to get the password or cookies.
Signed-off-by: Jonathon Jongsma <jjongsma(a)redhat.com>
---
[...]
diff --git a/src/qemu/qemu_nbdkit.c b/src/qemu/qemu_nbdkit.c
index 0ecf6c6537..2b8e203d16 100644
--- a/src/qemu/qemu_nbdkit.c
+++ b/src/qemu/qemu_nbdkit.c
@@ -55,6 +55,76 @@ VIR_ENUM_IMPL(qemuNbdkitCaps,
"filter-readahead", /* QEMU_NBDKIT_CAPS_FILTER_READAHEAD */
);
+
+static void
+nbdkitPipeItemFree(NbdkitPipeItem *item)
Please use consistent function naming, both for the function and for the
data.
+{
+ if (item->buf) {
+ virSecureErase(item->buf, item->buflen);
+ g_free(item->buf);
+ }
+
+ if (item->fd > 0)
+ VIR_FORCE_CLOSE(item->fd);
+
+ g_free(item);
+}
+
+
+void nbdkitPipeDataFree(NbdkitPipeData *self)
And consistent header formatting.
+{
+ size_t i;
+
+ if (!self)
+ return;
+
+ for (i = 0; i < self->nitems; i++) {
+ nbdkitPipeItemFree(self->items[i]);
+ }
+
+ g_free(self->items);
+ g_free(self);
+}
+
+
+static NbdkitPipeItem*
+nbdkitPipeItemNew(int fd, void *data, int datalen)
+{
+ NbdkitPipeItem *d;
+
+ if (!data || datalen == 0)
+ return NULL;
+
+ d = g_new0(NbdkitPipeItem, 1);
+ d->fd = fd;
+
+ if (datalen < 0) {
+ /* -1 indicates a null-terminated string */
+ d->buf = g_strdup(data);
+ d->buflen = strlen(data);
+ } else {
+ d->buf = g_malloc(datalen);
+ memcpy(d->buf, data, datalen);
+ d->buflen = datalen;
+ }
+
+ return d;
+}
+
+
+static int
+nbdkitPipeDataWrite(NbdkitPipeItem *pipe)
+{
+ if (safewrite(pipe->fd, pipe->buf, pipe->buflen) < 0) {
Note that the pipes created by virPipe are not non-blocking. This call
will block if you write into the pipe more than 64kiB on linux.
Normally the size should be enough but you at least need to have
something preventing the process getting stuck.
I think the best case would be if virCommand allowed simply being passed
a buffer and serving the pipes automatically.
+ virReportSystemError(errno,
+ _("failed to write data to pipe %i for nbdkit"),
+ pipe->fd);
+ return -1;
+ }
+ return 0;
+}
+
+
struct _qemuNbdkitCaps {
GObject parent;
[...]
@@ -685,12 +761,36 @@ qemuNbdkitInitStorageSource(qemuNbdkitCaps
*caps,
}
+static NbdkitPipeItem*
+commandPassDataByPipe(virCommand *cmd,
Again inconsistent naming.
+ const char *argName,
+ char *buf,
+ size_t buflen)
+{
+ int fds[2] = { -1, -1 };
+ g_autofree char *fdfmt = NULL;
+
+ if (virPipe(fds) < 0)
+ return NULL;
+
+ /* some nbdkit arguments accept a variation where nbdkit will read the data
+ * from a file descriptor, e.g. password=-FD */
+ fdfmt = g_strdup_printf("-%i", fds[PIPE_FD_READ]);
+ virCommandAddArgPair(cmd, argName, fdfmt);
+ virCommandPassFD(cmd, fds[PIPE_FD_READ], VIR_COMMAND_PASS_FD_CLOSE_PARENT);
+
+ return nbdkitPipeItemNew(fds[PIPE_FD_WRITE], (char*)buf, buflen);
+}
+
static int
qemuNbdkitProcessBuildCommandCurl(qemuNbdkitProcess *proc,
- virCommand *cmd)
+ virCommand *cmd,
+ NbdkitPipeData **pipeData)
{
g_autoptr(virURI) uri = qemuBlockStorageSourceGetURI(proc->source);
g_autofree char *uristring = virURIFormat(uri);
+ g_autoptr(GPtrArray) pipes =
+ g_ptr_array_new_with_free_func((GDestroyNotify)nbdkitPipeDataFree);
A GSlist or GList would also do well here since you never actually
randomly access the elements thus don't need them to be numbered.
/* nbdkit plugin name */
virCommandAddArg(cmd, "curl");
[...]