[libvirt] [PATCH 0/2] Fix some errors around VIR_ACCESS_DENIED

Patch 1 fixes my own error made in this release fortunately, but only seen because I was invesigating Patch 2 Patch 2 is perhaps a longer term issue, but perhaps coming more to light now that the nwfilter bindings have been separated and use a virConnectOpen for nwfilter:///system during reconnection processing; whereas, previously the filter bindings would have been "hidden" within various nwfilter, domain, and network driver callbacks and throughs. John Ferlan (2): util: Fix VIR_ERR_ACCESS_DENIED formatting qemu: Set identity for the reconnect all thread src/qemu/qemu_process.c | 5 +++++ src/util/virerror.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) -- 2.17.2

In commit ccc72d5cb I thought I had the brilliant idea that I could alter an error message in virErrorMsg to take two arguments "drivername" and NULL. Then passing the failed drivername for VIR_ERR_ACCESS_DENIED users would magically allow any "real" error message to be included. Of course it worked for the majority of errors, except for 1 teeny, tiny, problem - there was a caller using VIR_ERR_ACCESS_DENIED that actually passed "real" error message - virAccessDriverPolkitGetCaller, but didn't pass a driver name. So when this code went to call virErrorMsg it resulted in garbage being printed in that second argument because that's not how things are written. So in order to avoid that issue, reset the error back to the usual if info == NULL, the print just some text; otherwise, print a formatted output. For a majority of error messages this will print the driver name after "access deined from:". For the one case in question, the correct error message will be displayed and no garbage chars. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/util/virerror.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/virerror.c b/src/util/virerror.c index 10f1b55c5f..df239bf371 100644 --- a/src/util/virerror.c +++ b/src/util/virerror.c @@ -1442,9 +1442,9 @@ virErrorMsg(virErrorNumber error, const char *info) break; case VIR_ERR_ACCESS_DENIED: if (info == NULL) - errmsg = _("access denied from '%s'"); + errmsg = _("access denied"); else - errmsg = _("access denied from '%s': %s"); + errmsg = _("access denied from: %s"); break; case VIR_ERR_DBUS_SERVICE: if (info == NULL) -- 2.17.2

On Fri, Nov 09, 2018 at 19:39:36 -0500, John Ferlan wrote:
In commit ccc72d5cb I thought I had the brilliant idea that I could alter an error message in virErrorMsg to take two arguments "drivername" and NULL. Then passing the failed drivername for VIR_ERR_ACCESS_DENIED users would magically allow any "real" error message to be included. Of course it worked for the majority of errors, except for 1 teeny, tiny, problem - there was a caller using VIR_ERR_ACCESS_DENIED that actually passed "real" error message - virAccessDriverPolkitGetCaller, but didn't pass a driver name. So when this code went to call virErrorMsg it resulted in garbage being printed in that second argument because that's not how things are written.
So in order to avoid that issue, reset the error back to the usual if info == NULL, the print just some text; otherwise, print a formatted output. For a majority of error messages this will print the driver name after "access deined from:". For the one case in question, the correct error message will be displayed and no garbage chars.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/util/virerror.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/util/virerror.c b/src/util/virerror.c index 10f1b55c5f..df239bf371 100644 --- a/src/util/virerror.c +++ b/src/util/virerror.c @@ -1442,9 +1442,9 @@ virErrorMsg(virErrorNumber error, const char *info) break; case VIR_ERR_ACCESS_DENIED: if (info == NULL) - errmsg = _("access denied from '%s'"); + errmsg = _("access denied"); else - errmsg = _("access denied from '%s': %s"); + errmsg = _("access denied from: %s"); break;
The referenced patch modifies virAccessManagerSanitizeError which passes a bogus NULL to virAccessError. Ideally the format string will be changed to just "%s" so that 'driverName' can't be interpreted as a format string. Additionally the referenced patch also modifies src/rpc/gendispatch.pl which also passes a bogus NULL to virReportError, which should be fixed as well. As a side-note, the original commit also attempted to print NULL pointers with %s modifier with *printf which is undefined behavior.

https://bugzilla.redhat.com/show_bug.cgi?id=1631622 If polkit authentication is enabled, an attempt to open the connection failed during virAccessDriverPolkitGetCaller when the call to virIdentityGetCurrent returned NULL resulting in the errors: virAccessDriverPolkitGetCaller:87 : access denied from: Policy kit denied action org.libvirt.api.connect.getattr from <anonymous> virAccessManagerSanitizeError:204 : access denied from: nwfilter Because qemuProcessReconnect runs in a thread during daemonRunStateInit processing it doesn't have the thread local identity. Thus when the virGetConnectNWFilter is called as part of the qemuProcessFiltersInstantiate when virDomainConfNWFilterInstantiate is run the attempt to get the idenity fails and results in the anonymous error above. To fix this, let's grab/use the virIdenityPtr of the process that will be creating the thread, e.g. what daemonRunStateInit has set and use that for our thread. That way any other similar processing that uses/requires an identity for any other call that would have previously been successfully run won't fail in a similar manner. Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_process.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 06a65b44e4..93f6a2279a 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -81,6 +81,7 @@ #include "netdev_bandwidth_conf.h" #include "virresctrl.h" #include "virvsock.h" +#include "viridentity.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -7716,6 +7717,7 @@ qemuProcessRefreshCPU(virQEMUDriverPtr driver, struct qemuProcessReconnectData { virQEMUDriverPtr driver; virDomainObjPtr obj; + virIdentityPtr identity; }; /* * Open an existing VM's monitor, re-detect VCPU threads @@ -7753,6 +7755,7 @@ qemuProcessReconnect(void *opaque) bool retry = true; bool tryMonReconn = false; + virIdentitySetCurrent(data->identity); VIR_FREE(data); qemuDomainObjRestoreJob(obj, &oldjob); @@ -7979,6 +7982,7 @@ qemuProcessReconnect(void *opaque) virObjectUnref(cfg); virObjectUnref(caps); virNWFilterUnlockFilterUpdates(); + virIdentitySetCurrent(NULL); return; error: @@ -8022,6 +8026,7 @@ qemuProcessReconnectHelper(virDomainObjPtr obj, memcpy(data, src, sizeof(*data)); data->obj = obj; + data->identity = virIdentityGetCurrent(); virNWFilterReadLockFilterUpdates(); -- 2.17.2

On Fri, Nov 09, 2018 at 19:39:37 -0500, John Ferlan wrote:
https://bugzilla.redhat.com/show_bug.cgi?id=1631622
If polkit authentication is enabled, an attempt to open the connection failed during virAccessDriverPolkitGetCaller when the call to virIdentityGetCurrent returned NULL resulting in the errors:
virAccessDriverPolkitGetCaller:87 : access denied from: Policy kit denied action org.libvirt.api.connect.getattr from <anonymous>
virAccessManagerSanitizeError:204 : access denied from: nwfilter
Because qemuProcessReconnect runs in a thread during daemonRunStateInit processing it doesn't have the thread local identity. Thus when the virGetConnectNWFilter is called as part of the qemuProcessFiltersInstantiate when virDomainConfNWFilterInstantiate is run the attempt to get the idenity fails and results in the anonymous error above.
To fix this, let's grab/use the virIdenityPtr of the process that will be creating the thread, e.g. what daemonRunStateInit has set and use that for our thread. That way any other similar processing that uses/requires an identity for any other call that would have previously been successfully run won't fail in a similar manner.
Signed-off-by: John Ferlan <jferlan@redhat.com> --- src/qemu/qemu_process.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 06a65b44e4..93f6a2279a 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -81,6 +81,7 @@ #include "netdev_bandwidth_conf.h" #include "virresctrl.h" #include "virvsock.h" +#include "viridentity.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -7716,6 +7717,7 @@ qemuProcessRefreshCPU(virQEMUDriverPtr driver, struct qemuProcessReconnectData { virQEMUDriverPtr driver; virDomainObjPtr obj; + virIdentityPtr identity; }; /* * Open an existing VM's monitor, re-detect VCPU threads @@ -7753,6 +7755,7 @@ qemuProcessReconnect(void *opaque) bool retry = true; bool tryMonReconn = false;
+ virIdentitySetCurrent(data->identity);
This takes it's own reference to the identity. The reference in data->identity is then leaked.
VIR_FREE(data);
qemuDomainObjRestoreJob(obj, &oldjob); @@ -7979,6 +7982,7 @@ qemuProcessReconnect(void *opaque) virObjectUnref(cfg); virObjectUnref(caps); virNWFilterUnlockFilterUpdates(); + virIdentitySetCurrent(NULL); return;
error: @@ -8022,6 +8026,7 @@ qemuProcessReconnectHelper(virDomainObjPtr obj,
memcpy(data, src, sizeof(*data)); data->obj = obj; + data->identity = virIdentityGetCurrent();
In addition to the leak from the thread, the reference is also leaked if the thread creation fails.
participants (2)
-
John Ferlan
-
Peter Krempa