
On 05/02/2013 12:06 PM, Laine Stump wrote:
This should resolve https://bugzilla.redhat.com/show_bug.cgi?id=958907
Recent new addition of code to read/write active network state to the NETWORK_STATE_DIR in the network driver broke startup for qemu:///session. The network driver had several state file paths hardcoded to /var, which could never possibly work in session mode.
This patch modifies *all* state files to use a variable string that is set differently according to whether or not we're running privileged.
There are very definitely other problems preventing dnsmasq and radvd from running in non-privileged mode, but it's more consistent to have the directories used by them be determined in the same fashion. --- src/network/bridge_driver.c | 155 ++++++++++++++++++++++++++++---------------- 1 file changed, 100 insertions(+), 55 deletions(-)
-#define NETWORK_PID_DIR LOCALSTATEDIR "/run/libvirt/network"
So previously, this constant represented the network runtime directory relative to the configured state dir (default /var in a distro installation)...
-#define NETWORK_STATE_DIR LOCALSTATEDIR "/lib/libvirt/network" +#define NETWORK_PID_DIR "/run/libvirt/network"
Now it is just the relative suffix of an (as-yet) unspecified prefix...
@@ -84,6 +83,10 @@ struct network_driver { iptablesContext *iptables; char *networkConfigDir; char *networkAutostartDir; + char *stateDir; + char *pidDir; + char *dnsmasqStateDir; + char *radvdStateDir;
...where the appropriate prefix is computed at initialization and stored for later use...
char *logDir; dnsmasqCapsPtr dnsmasqCaps; }; @@ -133,8 +136,8 @@ networkDnsmasqLeaseFileNameDefault(const char *netname) { char *leasefile;
- ignore_value(virAsprintf(&leasefile, DNSMASQ_STATE_DIR "/%s.leases", - netname)); + ignore_value(virAsprintf(&leasefile, "%s/%s.leases", + driverState->dnsmasqStateDir, netname));
...all uses now use the computed value instead of the hard-coded macro...
@@ -374,27 +380,59 @@ networkStateInitialize(bool privileged, networkDriverLock(driverState);
if (privileged) { - if (virAsprintf(&driverState->logDir, - "%s/log/libvirt/qemu", LOCALSTATEDIR) == -1) - goto out_of_memory; - - if ((base = strdup(SYSCONFDIR "/libvirt")) == NULL) + if (((base = strdup(SYSCONFDIR "/libvirt")) == NULL) || + ((driverState->logDir + = strdup(LOCALSTATEDIR "/log/libvirt/qemu")) == NULL) || + ((driverState->stateDir + = strdup(LOCALSTATEDIR NETWORK_STATE_DIR)) == NULL) ||
...privileged initialization uses LOCALSTATEDIR as its location where the now-relative NETWORK_STATE_DIR is placed,...[1]
+ ((driverState->pidDir + = strdup(LOCALSTATEDIR NETWORK_PID_DIR)) == NULL) || + ((driverState->dnsmasqStateDir + = strdup(LOCALSTATEDIR DNSMASQ_STATE_DIR)) == NULL) || + ((driverState->radvdStateDir + = strdup(LOCALSTATEDIR RADVD_STATE_DIR)) == NULL)) { goto out_of_memory; + } } else { char *userdir = virGetUserCacheDirectory();
userdir is now malloc'd...[2]
if (!userdir) goto error;
+ userdir = virGetUserConfigDirectory();
[2]...but this overwrites it. Oops.
+ if (virAsprintf(&base, "%s", userdir) < 0) { + VIR_FREE(userdir); + goto out_of_memory; + } + VIR_FREE(userdir);
Huh? Simplify this to: base = virGetUserConfigDirectory(); no need to waste a malloc on userdir, just to re-malloc an identical copy of it into base via a beefy virAsprintf call.
+ if (virAsprintf(&driverState->logDir, - "%s/qemu/log", userdir) == -1) { + "%s/qemu/log", userdir) < 0) {
Huh? Use-after-free of userdir. Did you mean base?
VIR_FREE(userdir); goto out_of_memory; } VIR_FREE(userdir);
- userdir = virGetUserConfigDirectory(); - if (virAsprintf(&base, "%s", userdir) == -1) { + if (!(userdir = virGetUserRuntimeDirectory())) + goto error; + + if (virAsprintf(&driverState->stateDir, + "%s" NETWORK_STATE_DIR, userdir) < 0) {
[2]...for non-privileged code, we are now using the directory relative to the user directory. The idea makes sense, but your implementation of the idea on the qemu:///session side of things needs work.
+ if (virAsprintf(&driverState->pidDir, + "%s" NETWORK_PID_DIR, userdir) < 0) { + VIR_FREE(userdir); + goto out_of_memory; + } + if (virAsprintf(&driverState->dnsmasqStateDir, + "%s" DNSMASQ_STATE_DIR, userdir) < 0) { + VIR_FREE(userdir); + goto out_of_memory; + } + if (virAsprintf(&driverState->radvdStateDir, + "%s" RADVD_STATE_DIR, userdir) < 0) { VIR_FREE(userdir); goto out_of_memory;
That's a lot of VIR_FREE(userdir) calls; can you just pre-initialize it to NULL and just blindly move the VIR_FREE(userdir) into the out_of_memory label? Or even chain the conditionals: if (virAsprintf(&driverState->pidDir, "%s" NETWORK_PID_DIR, userdir) < 0 || virAsprintf(&driverState->dnsmasqStateDir, "%s" DNSMASQ_STATE_DIR, userdir) < 0 || ... Looking forward to v2. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org