diff options
| author | Pavel Březina <pbrezina@redhat.com> | 2016-07-15 14:50:41 +0200 |
|---|---|---|
| committer | Lukas Slebodnik <lslebodn@redhat.com> | 2016-08-16 14:54:31 +0200 |
| commit | 5d556f70f00c43864d8495d7caacfadf962799df (patch) | |
| tree | 2bcf1a208691413f04b52c36475055e2a252fc46 /src/sbus | |
| parent | de5160e354c02020f0593c7cabdb811107d5d8e2 (diff) | |
| download | sssd-5d556f70f00c43864d8495d7caacfadf962799df.tar.gz sssd-5d556f70f00c43864d8495d7caacfadf962799df.tar.xz sssd-5d556f70f00c43864d8495d7caacfadf962799df.zip | |
sbus: allow freeing msg through dbus api when using talloc
When a talloc-bound message was freed by removing all references
to it with dbus_message_unref we failed to free the talloc context
and thus leaking memory or unreferencing invalid message when
the parent context is freed.
This patch allows to bound dbus message to talloc in the way that
allows us to free the message by both talloc and dbus api.
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
Diffstat (limited to 'src/sbus')
| -rw-r--r-- | src/sbus/sssd_dbus_utils.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/src/sbus/sssd_dbus_utils.c b/src/sbus/sssd_dbus_utils.c index 4c33f9fd7..b0150e2fe 100644 --- a/src/sbus/sssd_dbus_utils.c +++ b/src/sbus/sssd_dbus_utils.c @@ -25,22 +25,52 @@ struct sbus_talloc_msg { DBusMessage *msg; + dbus_int32_t data_slot; + bool in_talloc_destructor; }; static int sbus_talloc_msg_destructor(struct sbus_talloc_msg *talloc_msg) { + talloc_msg->in_talloc_destructor = true; + if (talloc_msg->msg == NULL) { return 0; } + /* There may exist more references to this message but this talloc + * context is no longer valid. We remove dbus message data to invoke + * dbus destructor now. */ + dbus_message_set_data(talloc_msg->msg, talloc_msg->data_slot, NULL, NULL); dbus_message_unref(talloc_msg->msg); return 0; } +static void sbus_msg_data_destructor(void *ctx) +{ + struct sbus_talloc_msg *talloc_msg; + + talloc_msg = talloc_get_type(ctx, struct sbus_talloc_msg); + + dbus_message_free_data_slot(&talloc_msg->data_slot); + + if (!talloc_msg->in_talloc_destructor) { + /* References to this message dropped to zero but through + * dbus_message_unref(), not by calling talloc_free(). We need to free + * the talloc context and avoid running talloc desctuctor. */ + talloc_set_destructor(talloc_msg, NULL); + talloc_free(talloc_msg); + } +} + errno_t sbus_talloc_bound_message(TALLOC_CTX *mem_ctx, DBusMessage *msg) { struct sbus_talloc_msg *talloc_msg; + dbus_int32_t data_slot = -1; + DBusFreeFunction free_fn; + dbus_bool_t bret; + /* Create a talloc context that will unreference this message when + * the parent context is freed. */ talloc_msg = talloc(mem_ctx, struct sbus_talloc_msg); if (talloc_msg == NULL) { DEBUG(SSSDBG_CRIT_FAILURE, @@ -48,7 +78,28 @@ errno_t sbus_talloc_bound_message(TALLOC_CTX *mem_ctx, DBusMessage *msg) return ENOMEM; } + /* Allocate a dbus message data slot that will contain point to the + * talloc context so we can pick up cases when the dbus message is + * freed through dbus api. */ + bret = dbus_message_allocate_data_slot(&data_slot); + if (!bret) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to allocate data slot!\n"); + talloc_free(talloc_msg); + return ENOMEM; + } + + free_fn = sbus_msg_data_destructor; + bret = dbus_message_set_data(msg, data_slot, talloc_msg, free_fn); + if (!bret) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set message data!\n"); + talloc_free(talloc_msg); + dbus_message_free_data_slot(&data_slot); + return ENOMEM; + } + talloc_msg->msg = msg; + talloc_msg->data_slot = data_slot; + talloc_msg->in_talloc_destructor = false; talloc_set_destructor(talloc_msg, sbus_talloc_msg_destructor); |
