mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Philipp Reisner <philipp.reisner@linbit.com>
To: linux-kernel@vger.kernel.org, Jens Axboe <axboe@kernel.dk>
Cc: drbd-dev@lists.linbit.com
Subject: [PATCH 18/19] drbd: fix NULL deref in remember_new_state
Date: Thu, 30 Jul 2015 13:21:53 +0200	[thread overview]
Message-ID: <1438255314-14877-19-git-send-email-philipp.reisner@linbit.com> (raw)
In-Reply-To: <1438255314-14877-1-git-send-email-philipp.reisner@linbit.com>

From: Lars Ellenberg <lars.ellenberg@linbit.com>

The recent (not yet released) backport of the extended state broadcasts
to support the "events2" subcommand of drbdsetup had some glitches.

remember_old_state() would first count all connections with a
net_conf != NULL, then allocate a suitable array, then populate that
array with all connections found to have net_conf != NULL.

This races with the state change to C_STANDALONE,
and the NULL assignment there.

remember_new_state() then iterates over said connection array,
assuming that it would be fully populated.

But rcu_lock() just makes sure the thing some pointer points to,
if any, won't go away. It does not make the pointer itself immutable.

In fact there is no need to "filter" connections based on whether or not
they have a currently valid configuration.  Just record them always, if
they don't have a config, that's fine, there will be no change then.

Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
---
 drivers/block/drbd/drbd_state.c | 46 +++++++++++++----------------------------
 1 file changed, 14 insertions(+), 32 deletions(-)

diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c
index a4e4505..f022e99 100644
--- a/drivers/block/drbd/drbd_state.c
+++ b/drivers/block/drbd/drbd_state.c
@@ -63,11 +63,8 @@ static void count_objects(struct drbd_resource *resource,
 
 	idr_for_each_entry(&resource->devices, device, vnr)
 		(*n_devices)++;
-	for_each_connection(connection, resource) {
-		if (!has_net_conf(connection))
-			continue;
+	for_each_connection(connection, resource)
 		(*n_connections)++;
-	}
 }
 
 static struct drbd_state_change *alloc_state_change(unsigned int n_devices, unsigned int n_connections, gfp_t gfp)
@@ -108,23 +105,13 @@ struct drbd_state_change *remember_old_state(struct drbd_resource *resource, gfp
 	struct drbd_peer_device_state_change *peer_device_state_change;
 	struct drbd_connection_state_change *connection_state_change;
 
-retry:
-	rcu_read_lock();
+	/* Caller holds req_lock spinlock.
+	 * No state, no device IDR, no connections lists can change. */
 	count_objects(resource, &n_devices, &n_connections);
-	rcu_read_unlock();
 	state_change = alloc_state_change(n_devices, n_connections, gfp);
 	if (!state_change)
 		return NULL;
 
-	rcu_read_lock();
-	count_objects(resource, &n_devices, &n_connections);
-	if (n_devices != state_change->n_devices ||
-	    n_connections != state_change->n_connections) {
-		kfree(state_change);
-		rcu_read_unlock();
-		goto retry;
-	}
-
 	kref_get(&resource->kref);
 	state_change->resource->resource = resource;
 	state_change->resource->role[OLD] =
@@ -133,6 +120,17 @@ retry:
 	state_change->resource->susp_nod[OLD] = resource->susp_nod;
 	state_change->resource->susp_fen[OLD] = resource->susp_fen;
 
+	connection_state_change = state_change->connections;
+	for_each_connection(connection, resource) {
+		kref_get(&connection->kref);
+		connection_state_change->connection = connection;
+		connection_state_change->cstate[OLD] =
+			connection->cstate;
+		connection_state_change->peer_role[OLD] =
+			conn_highest_peer(connection);
+		connection_state_change++;
+	}
+
 	device_state_change = state_change->devices;
 	peer_device_state_change = state_change->peer_devices;
 	idr_for_each_entry(&resource->devices, device, vnr) {
@@ -145,8 +143,6 @@ retry:
 		for_each_connection(connection, resource) {
 			struct drbd_peer_device *peer_device;
 
-			if (!has_net_conf(connection))
-				continue;
 			peer_device = conn_peer_device(connection, device->vnr);
 			peer_device_state_change->peer_device = peer_device;
 			peer_device_state_change->disk_state[OLD] =
@@ -165,20 +161,6 @@ retry:
 		device_state_change++;
 	}
 
-	connection_state_change = state_change->connections;
-	for_each_connection(connection, resource) {
-		if (!has_net_conf(connection))
-			continue;
-		kref_get(&connection->kref);
-		connection_state_change->connection = connection;
-		connection_state_change->cstate[OLD] =
-			connection->cstate;
-		connection_state_change->peer_role[OLD] =
-			conn_highest_peer(connection);
-		connection_state_change++;
-	}
-	rcu_read_unlock();
-
 	return state_change;
 }
 
-- 
1.9.1


  parent reply	other threads:[~2015-07-30 11:33 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-07-30 11:21 [PATCH 00/19] RFC DRBD updates for the 4.3 merge window Philipp Reisner
2015-07-30 11:21 ` [PATCH 01/19] drbd: Remove pointless check Philipp Reisner
2015-07-30 11:21 ` [PATCH 02/19] drbd: De-inline drbd_should_do_remote() and drbd_should_send_out_of_sync() Philipp Reisner
2015-07-30 11:21 ` [PATCH 03/19] drbd: Get rid of some first_peer_device() calls Philipp Reisner
2015-07-30 11:21 ` [PATCH 04/19] drbd: Move enum write_ordering_e to drbd.h Philipp Reisner
2015-07-30 11:21 ` [PATCH 05/19] drbd: drbd_adm_attach(): Add missing drbd_resync_after_changed() Philipp Reisner
2015-07-30 11:21 ` [PATCH 06/19] drbd: Fix locking across all resources Philipp Reisner
2015-07-30 11:21 ` [PATCH 07/19] drbd: Backport the "events2" command Philipp Reisner
2015-07-30 11:21 ` [PATCH 08/19] drbd: Backport the "status" command Philipp Reisner
2015-07-30 11:21 ` [PATCH 09/19] drbd: Deletion of an unnecessary check before the function call "lc_destroy" Philipp Reisner
2015-07-30 11:21 ` [PATCH 10/19] drbd: Replace 0 with the more meaningful GFP_NOWAIT Philipp Reisner
2015-07-30 11:21 ` [PATCH 11/19] drbd: Fix spurious disk-timeout Philipp Reisner
2015-07-30 11:21 ` [PATCH 12/19] drbd: drop remnants of connector -- we don't use it anymore in drbd 8.4 Philipp Reisner
2015-07-30 11:21 ` [PATCH 13/19] drbd: drbdsetup detach of an unresponsive local disk should not block IO "forever" Philipp Reisner
2015-07-30 11:21 ` [PATCH 14/19] drbd: also bump UUIDs if a diskless primary connects Philipp Reisner
2015-07-30 11:21 ` [PATCH 15/19] drbd: add comment why we want to first call local-io-error, then send state Philipp Reisner
2015-07-30 11:21 ` [PATCH 16/19] drbd: drbd_panic_after_delayed_completion_of_aborted_request() Philipp Reisner
2015-07-30 11:21 ` [PATCH 17/19] drbd: improve network timeout detection Philipp Reisner
2015-07-30 11:21 ` Philipp Reisner [this message]
2015-07-30 11:21 ` [PATCH 19/19] drbd: fix refcount error during detach of an already failed disk Philipp Reisner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1438255314-14877-19-git-send-email-philipp.reisner@linbit.com \
    --to=philipp.reisner@linbit.com \
    --cc=axboe@kernel.dk \
    --cc=drbd-dev@lists.linbit.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®