From 99e6b9789bb569848629b84cf5c9654f8c3bc8cc Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Mon, 12 Jan 2015 12:39:03 +0100 Subject: [PATCH] connection: fix dead-lock on policy-removal If we clear the policy-db on last kdbus_conn_unref(), we have to take the policy semaphore. However, we allow calling kdbus_conn_unref() while holding a connection lock. This might deadlock against normal policy-db modifications. Therefore, we move policy-setup _after_ kdbus_conn_connect() and ensure the connection is active. Then we can move the policy-removal into kdbus_conn_disconnect(), which itself must never be called while holding any lock. Signed-off-by: David Herrmann --- connection.c | 15 +-------------- handle.c | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/connection.c b/connection.c index 654fc83..d7357b6 100644 --- a/connection.c +++ b/connection.c @@ -887,6 +887,7 @@ int kdbus_conn_disconnect(struct kdbus_conn *conn, bool ensure_queue_empty) #endif cancel_delayed_work_sync(&conn->work); + kdbus_policy_remove_owner(&conn->ep->bus->policy_db, conn); /* lock order: domain -> bus -> ep -> names -> conn */ mutex_lock(&conn->ep->lock); @@ -984,8 +985,6 @@ static void __kdbus_conn_free(struct kref *kref) kdbus_domain_user_unref(conn->user); } - kdbus_policy_remove_owner(&conn->ep->bus->policy_db, conn); - kdbus_meta_proc_unref(conn->meta); kdbus_match_db_free(conn->match_db); kdbus_pool_free(conn->pool); @@ -1572,18 +1571,6 @@ struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, goto exit_unref; } - if (is_activator || is_policy_holder) { - /* - * Policy holders may install one name, and are - * allowed to use wildcards. - */ - ret = kdbus_policy_set(&bus->policy_db, hello->items, - KDBUS_ITEMS_SIZE(hello, items), - 1, is_policy_holder, conn); - if (ret < 0) - goto exit_unref; - } - /* return properties of this connection to the caller */ hello->bus_flags = bus->bus_flags; hello->id = conn->id; diff --git a/handle.c b/handle.c index b1a1e8e..991dcd6 100644 --- a/handle.c +++ b/handle.c @@ -264,6 +264,23 @@ static int handle_ep_ioctl_hello(struct kdbus_handle_ep *handle, } ret = kdbus_conn_connect(conn, hello); + if (ret < 0) + goto exit_conn; + + ret = kdbus_conn_acquire(conn); + if (ret < 0) + goto exit_conn; + + if (kdbus_conn_is_activator(conn) || kdbus_conn_is_policy_holder(conn)) + ret = kdbus_policy_set(&conn->ep->bus->policy_db, hello->items, + KDBUS_ITEMS_SIZE(hello, items), + 1, kdbus_conn_is_policy_holder(conn), + conn); + else + ret = 0; + + kdbus_conn_release(conn); + if (ret < 0) goto exit_conn; -- 2.34.1