]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu_passt: Precreate passt logfile
authorMichal Privoznik <mprivozn@redhat.com>
Fri, 9 Jun 2023 06:59:18 +0000 (08:59 +0200)
committerMichal Privoznik <mprivozn@redhat.com>
Mon, 26 Jun 2023 13:52:54 +0000 (15:52 +0200)
There are a few situations where passt itself is unable to create
a file because it runs under QEMU user (e.g. just like our
example from formatdomain.rst suggests: /var/log/passt.log). If
libvirtd runs with sufficient permissions (e.g. as root) it can
create the file and set seclabels on it so that passt can then
open it.

Ideally, we would just pass pre-opened FD, but this wasn't viewed
as secure enough [1]. So lets just create the file and set
seclabels.

For the case when both libvirtd and passt have the same
permissions, well then we fail before even needing to fork() and
exec().

1: https://archives.passt.top/passt-dev/20230606225836.63aecebe@elisabeth/
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2209191
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
src/qemu/qemu_passt.c

index 99636a3a4955b2b71a54abe534c826d3a50e9701..25b22d8ad96299f950b9fc9aaa3162fcafd7ad0e 100644 (file)
@@ -20,6 +20,8 @@
 
 #include <config.h>
 
+#include <fcntl.h>
+
 #include "qemu_dbus.h"
 #include "qemu_extdevice.h"
 #include "qemu_security.h"
@@ -136,9 +138,13 @@ void
 qemuPasstStop(virDomainObj *vm,
               virDomainNetDef *net)
 {
+    qemuDomainObjPrivate *priv = vm->privateData;
+    virQEMUDriver *driver = priv->driver;
     g_autofree char *pidfile = qemuPasstCreatePidFilename(vm, net);
     g_autofree char *passtSocketName = qemuPasstCreateSocketPath(vm, net);
 
+    qemuSecurityDomainRestorePathLabel(driver, vm, net->backend.logFile);
+
     qemuPasstKill(pidfile, passtSocketName);
 }
 
@@ -166,10 +172,12 @@ qemuPasstStart(virDomainObj *vm,
 {
     qemuDomainObjPrivate *priv = vm->privateData;
     virQEMUDriver *driver = priv->driver;
+    g_autoptr(virQEMUDriverConfig) cfg = virQEMUDriverGetConfig(driver);
     g_autofree char *passtSocketName = qemuPasstCreateSocketPath(vm, net);
     g_autoptr(virCommand) cmd = NULL;
     g_autofree char *pidfile = qemuPasstCreatePidFilename(vm, net);
     char macaddr[VIR_MAC_STRING_BUFLEN];
+    bool needUnlink = false;
     size_t i;
 
     cmd = virCommandNew(PASST);
@@ -191,8 +199,25 @@ qemuPasstStart(virDomainObj *vm,
     if (net->sourceDev)
         virCommandAddArgList(cmd, "--interface", net->sourceDev, NULL);
 
-    if (net->backend.logFile)
+    if (net->backend.logFile) {
+        VIR_AUTOCLOSE logfd = -1;
+        /* The logFile location is not restricted to a per-domain directory. It
+         * can be anywhere. Pre-create it as passt may not have enough perms to
+         * do so. */
+        if (qemuDomainOpenFile(cfg, vm->def, net->backend.logFile,
+                               O_CREAT | O_TRUNC | O_APPEND | O_RDWR,
+                               &needUnlink) < 0) {
+            return -1;
+        }
+
+        if (qemuSecurityDomainSetPathLabel(driver, vm,
+                                           net->backend.logFile, false) < 0) {
+            goto error;
+        }
+
+        /* Worse, passt deliberately doesn't support FD passing. */
         virCommandAddArgList(cmd, "--log-file", net->backend.logFile, NULL);
+    }
 
     /* Add IP address info */
     for (i = 0; i < net->guestIP.nips; i++) {
@@ -203,7 +228,7 @@ qemuPasstStart(virDomainObj *vm,
          * a single IPv4 and single IPv6 address
          */
         if (!(addr = virSocketAddrFormat(&ip->address)))
-            return -1;
+            goto error;
 
         virCommandAddArgList(cmd, "--address", addr, NULL);
 
@@ -231,14 +256,14 @@ qemuPasstStart(virDomainObj *vm,
             /* validation guarantees this will never happen */
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("Invalid portForward proto value %1$u"), pf->proto);
-            return -1;
+            goto error;
         }
 
         if (VIR_SOCKET_ADDR_VALID(&pf->address)) {
             g_autofree char *addr = NULL;
 
             if (!(addr = virSocketAddrFormat(&pf->address)))
-                return -1;
+                goto error;
 
             virBufferAddStr(&buf, addr);
             emitsep = true;
@@ -284,7 +309,7 @@ qemuPasstStart(virDomainObj *vm,
 
 
     if (qemuExtDeviceLogCommand(driver, vm, cmd, "passt") < 0)
-        return -1;
+        goto error;
 
     if (qemuSecurityCommandRun(driver, vm, cmd, -1, -1, true, NULL) < 0)
         goto error;
@@ -292,6 +317,11 @@ qemuPasstStart(virDomainObj *vm,
     return 0;
 
  error:
+    if (needUnlink && unlink(net->backend.logFile) < 0) {
+        VIR_WARN("Unable to unlink '%s': %s",
+                 net->backend.logFile, g_strerror(errno));
+    }
+
     qemuPasstKill(pidfile, passtSocketName);
     return -1;
 }