From e58d1dc4b685568f51c00506d81ab12b95be8d4a Mon Sep 17 00:00:00 2001 From: Martin Schwenke Date: Mon, 6 May 2019 15:22:49 +1000 Subject: [PATCH] ctdb-daemon: Never use 0 as a client ID ctdb_control_db_attach() and ctdb_control_db_detach() assume that any control with client ID 0 comes from another daemon and treat it specially. BUG: https://bugzilla.samba.org/show_bug.cgi?id=13930 Signed-off-by: Martin Schwenke Reviewed-by: Amitay Isaacs (cherry picked from commit 8663e0a64fbdb9ea16babbfe87d6f5d7a7b72bbd) --- ctdb/server/ctdb_daemon.c | 48 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/ctdb/server/ctdb_daemon.c b/ctdb/server/ctdb_daemon.c index a8691388d4a..aa0694548f8 100644 --- a/ctdb/server/ctdb_daemon.c +++ b/ctdb/server/ctdb_daemon.c @@ -928,6 +928,44 @@ static int ctdb_clientpid_destructor(struct ctdb_client_pid_list *client_pid) return 0; } +static int get_new_client_id(struct reqid_context *idr, + struct ctdb_client *client, + uint32_t *out) +{ + uint32_t client_id; + + client_id = reqid_new(idr, client); + /* + * Some places in the code (e.g. ctdb_control_db_attach(), + * ctdb_control_db_detach()) assign a special meaning to + * client_id 0. The assumption is that if client_id is 0 then + * the control has come from another daemon. Therefore, we + * should never return client_id == 0. + */ + if (client_id == 0) { + /* + * Don't leak ID 0. This is safe because the ID keeps + * increasing. A test will be added to ensure that + * this doesn't change. + */ + reqid_remove(idr, 0); + + client_id = reqid_new(idr, client); + } + + if (client_id == REQID_INVALID) { + return EINVAL; + } + + if (client_id == 0) { + /* Every other ID must have been used and we can't use 0 */ + reqid_remove(idr, 0); + return EINVAL; + } + + *out = client_id; + return 0; +} static void ctdb_accept_client(struct tevent_context *ev, struct tevent_fd *fde, uint16_t flags, @@ -971,7 +1009,15 @@ static void ctdb_accept_client(struct tevent_context *ev, client->ctdb = ctdb; client->fd = fd; - client->client_id = reqid_new(ctdb->idr, client); + + ret = get_new_client_id(ctdb->idr, client, &client->client_id); + if (ret != 0) { + DBG_ERR("Unable to get client ID (%d)\n", ret); + close(fd); + talloc_free(client); + return; + } + client->pid = peer_pid; client_pid = talloc(client, struct ctdb_client_pid_list); -- 2.20.1