From b864535791844ce4f9437cebefaf3c37b3741b4a Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Thu, 8 Jan 2015 21:06:14 +0100 Subject: bus-proxyd: fix EPERM on replies Imagine a kdbus peer sending a method-call without EXPECT_REPLY set through the proxy to a dbus1 peer. The proxy turns the missing EXPECT_REPLY flag into a dbus1 NO_REPLY_EXPECTED flag. However, if the receipient ignores that flag (valid dbus1 behavior) and sends a reply, the proxy will try to forward it to the original peer. This will fail with EPERM as the kernel didn't track the reply. We have two options now: Either we ignore EPERM for reply messages, or we track reply-windows in the proxy so we can properly ignore replies if EXPECT_REPLY wasn't set. This commit chose the first option: ignore EPERM for replies. The only down-side is that replies without matching method call will no longer be forwarded by the proxy. This works on dbus1, though. Nobody sane does this, so lets ignore it. --- src/bus-proxyd/bus-proxyd.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c index 44e16fcd15..21cd4e29d2 100644 --- a/src/bus-proxyd/bus-proxyd.c +++ b/src/bus-proxyd/bus-proxyd.c @@ -1605,14 +1605,26 @@ int main(int argc, char *argv[]) { if (!processed) { k = sd_bus_send(b, m, NULL); if (k < 0) { - if (k == -ECONNRESET) + if (k == -ECONNRESET) { r = 0; - else { + goto finish; + } else if (k == -EPERM && m->reply_cookie > 0) { + /* If the peer tries to send a reply and it is rejected with EPERM + * by the kernel, we ignore the error. This catches cases where the + * original method-call didn't had EXPECT_REPLY set, but the proxy-peer + * still sends a reply. This is allowed in dbus1, but not in kdbus. We + * don't want to track reply-windows in the proxy, so we simply ignore + * EPERM for all replies. The only downside is, that callers are no + * longer notified if their replies are dropped. However, this is + * equivalent to the caller's timeout to expire, so this should be + * acceptable. Nobody sane sends replies without a matching method-call, + * so nobody should care. */ + r = 1; + } else { r = k; log_error_errno(r, "Failed to send message to client: %m"); + goto finish; } - - goto finish; } else r = 1; } @@ -1682,17 +1694,20 @@ int main(int argc, char *argv[]) { k = sd_bus_send(a, m, NULL); if (k < 0) { - if (k == -EREMCHG) + if (k == -EREMCHG) { /* The name database changed since the policy check, hence let's check again */ continue; - else if (k == -ECONNRESET) + } else if (k == -ECONNRESET) { r = 0; - else { + goto finish; + } else if (k == -EPERM && m->reply_cookie > 0) { + /* see above why EPERM is ignored for replies */ + r = 1; + } else { r = k; log_error_errno(r, "Failed to send message to bus: %m"); + goto finish; } - - goto finish; } else r = 1; -- cgit v1.2.3-54-g00ecf