Dr. Werner Fink 2014-03-13 14:17:45 +00:00 committed by Git OBS Bridge
parent 17495bfa7f
commit 738fd16fab

View File

@ -1,36 +1,86 @@
From: Olaf Kirch <okir@suse.de>
Date: Date: Wed, 12 Mar 2014 13:52:50 +0000
Subject: [PATCH] systemd big endian reply matching
---
src/libsystemd/sd-bus/sd-bus.c | 36 +++++++++++++++++++++++++++++++-----
1 file changed, 31 insertions(+), 5 deletions(-)
Reply matching on big endian architectures is broken in the dbus code.
The hashmap functions, which are used to store and retrieves the reply_callback
structures of asynchronous calls, take a uint64_t pointer for the key argument.
However, the reply_cookie of the sd_bus_message is stored in a 32bit variable.
This works nicely on x86-64, because (a) it's little endian, and (b) the struct
is padded to the next 8 byte boundary because reply_cookie is wedged between
two pointers.
On s390x, this fails badly thanks to being big endian.
Unfortunately, this results in complete failure of any communication
between systemd daemons and the dbus-daemon, because it never gets
past the initial Hello handshake - which is sent as an asynchronous
message.
Signed-off-by: Olaf Kirch <okir@suse.de>
Index: systemd-210/src/libsystemd/sd-bus/bus-message.h
Index: systemd-210/src/libsystemd/sd-bus/sd-bus.c
===================================================================
--- systemd-210/src/libsystemd/sd-bus/bus-message.h
+++ systemd-210/src/libsystemd/sd-bus/bus-message.h
@@ -84,7 +84,7 @@ struct sd_bus_message {
--- systemd-210.orig/src/libsystemd/sd-bus/sd-bus.c
+++ systemd-210/src/libsystemd/sd-bus/sd-bus.c
@@ -358,6 +358,29 @@ _public_ int sd_bus_set_name(sd_bus *bus
return 0;
}
sd_bus *bus;
+/*
+ * Wrap the hashmap lookups in helper functions to ensure that the
+ * cookie pointer is always cast to 64bit before passing it to any of the
+ * hashmap functions
+ */
+static inline int bus_add_reply_callback(sd_bus *bus, struct reply_callback *c, uint64_t cookie)
+{
+ return hashmap_put(bus->reply_callbacks, &cookie, c);
+}
+
+static inline struct reply_callback *bus_get_reply_callback(sd_bus *bus, uint64_t cookie)
+{
+ return hashmap_remove(bus->reply_callbacks, &cookie);
+}
+
+static inline void bus_drop_reply_callback(sd_bus *bus, const struct reply_callback *c)
+{
+ struct reply_callback *cc;
+
+ cc = bus_get_reply_callback(bus, c->cookie);
+ assert(cc == NULL || cc == c);
+}
+
static int hello_callback(sd_bus *bus, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
const char *s;
int r;
@@ -1757,7 +1780,7 @@ _public_ int sd_bus_call_async(
c->cookie = BUS_MESSAGE_COOKIE(m);
c->timeout = calc_elapse(m->timeout);
- uint32_t reply_cookie;
+ uint64_t reply_cookie;
- r = hashmap_put(bus->reply_callbacks, &c->cookie, c);
+ r = bus_add_reply_callback(bus, c, c->cookie);
if (r < 0) {
free(c);
return r;
@@ -1788,7 +1811,7 @@ _public_ int sd_bus_call_async_cancel(sd
assert_return(cookie != 0, -EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
const char *path;
const char *interface;
- c = hashmap_remove(bus->reply_callbacks, &cookie);
+ c = bus_get_reply_callback(bus, cookie);
if (!c)
return 0;
@@ -2062,7 +2085,7 @@ static int process_timeout(sd_bus *bus)
return r;
assert_se(prioq_pop(bus->reply_callbacks_prioq) == c);
- hashmap_remove(bus->reply_callbacks, &c->cookie);
+ bus_drop_reply_callback(bus, c->cookie);
bus->current = m;
bus->iteration_counter ++;
@@ -2110,7 +2133,9 @@ static int process_reply(sd_bus *bus, sd
m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
return 0;
- c = hashmap_remove(bus->reply_callbacks, &m->reply_cookie);
+ /* caveat emptor: reply_cookie is 32bit, but the hashmap lookup uses a 64bit
+ * cookie pointer - without type checking, */
+ c = bus_get_reply_callback(bus, m->reply_cookie);
if (!c)
return 0;
@@ -2370,7 +2395,8 @@ static int process_closing(sd_bus *bus,
if (c->timeout != 0)
prioq_remove(bus->reply_callbacks_prioq, c, &c->prioq_idx);
- hashmap_remove(bus->reply_callbacks, &c->cookie);
+ /* Remove callback from reply_callbacks hashmap */
+ bus_drop_reply_callback(bus, c->cookie);
bus->current = m;
bus->iteration_counter++;