diff options
author | David Herrmann <dh.herrmann@gmail.com> | 2015-01-08 21:06:14 +0100 |
---|---|---|
committer | David Herrmann <dh.herrmann@gmail.com> | 2015-01-08 21:06:14 +0100 |
commit | b864535791844ce4f9437cebefaf3c37b3741b4a (patch) | |
tree | e427be9f2ee61762fc7bebe9bf3f655691c1cea0 | |
parent | 426bb5ddb8ff122d3e08b0480466718b68485e70 (diff) |
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.
-rw-r--r-- | src/bus-proxyd/bus-proxyd.c | 33 |
1 files changed, 24 insertions, 9 deletions
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; |